【NOI 2005】 维修数列
【题目链接】
【算法】
本题所运用的也是Splay的区间操作,但是实现较为困难
INSERT操作
将pos splay至根节点,pos+1 splay至根节点的右节点,然后对根节点的右节点的左节点建树即可
DELETE操作
将l-1 splay至根节点, r+1 splay至根节点的右节点,直接“砍断”根节点的右节点的左节点
MAKE_SAME操作
将l-1 splay至根节点,r+1 splay至根节点的右节点,给根节点的右节点的左节点打上标记
REVERSE操作
将l-1 splay至根节点,r+1 splay至根节点的右节点,给根节点的右节点的左节点打上标记
GET_SUM操作
将l-1 splay至根节点,r+1 splay至根节点的右节点,直接输出根节点的右节点的左节点的sum
MAX_SUM操作
此操作的实现类似于树形DP :
我们不妨给每个节点增加三个域
lmax :从这个节点所代表的区间的左端点开始向右延伸的最大和
rmax :从这个节点所代表的区间的右端点开始像左延伸的最大和
max : 该节点所代表区间的最大连续子段和
那么,lmax该如何取值?
令根节点为root,根节点的左儿子为lc,根节点的右儿子为rc
我们可以分情况讨论 :
若lmax[root]不包括root,则lmax[root] = lmax[lc]
若lmax[root]包括root,那么 : 若不向右继续延伸,则lmax[root] = tot[lc] + val[root],若向右延伸,
则lmax[root] = tot[lc] + val[root] + lmax[rc]
我们只要在这三者中取最大值就可以了
rmax同理
那么,max又该如何取值呢?
我们还是分情况讨论 :
令根节点为root,根节点的左儿子为rc,根节点的右儿子为rc
若max[root]不包括root,则max[root] = max{max[lc],max[rc]}
若max[root]包括root,那么 : 若不向右也不向左延伸,则max[root] = val[root],若向左延伸,
则max[root] = val[root] + rmax[lc]
若向右延伸,则 :
max[root] = val[root] + lmax[rc]
若两边同时延伸,则 :
max[root] = val[root] + rmax[rc] + lmax[lc]
只需在这五者中取最大值即可
关于内存池 :
由于本题数据量较大,我们要进行内存回收,内存回收方法如下 :
我们建立一个内存池,开始时将所有可用空间都放入内存池,插入一个节点时,我们从内存池弹出一个节点,
分配给这个节点,删除时,我们将要删除的节点放回内存池,如果是删除一棵子树,则将整棵子树放回内存池
这个内存池可以用栈,队列,链表等许多数据结构来维护,笔者选用的是栈,由于维护方法比较简单,笔者不再赘述
【代码】
本题的细节很多,写代码时一定要严谨!
#include<bits/stdc++.h>
using namespace std;
#define MAXN 20000
#define MAXX 500000
const int INF = 2e9; int i,N,M,tot,pos,val;
int a[MAXX+];
char opt[];
stack<int> stk; template <typename T> inline void read(T &x) {
int f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; }
for (; isdigit(c); c = getchar()) x = x * + c - '';
x *= f;
} template <typename T> inline void write(T x) {
if (x < ) { putchar('-'); x = -x; }
if (x > ) write(x/);
putchar(x%+'');
} template <typename T> inline void writeln(T x) {
write(x);
puts("");
} struct Splay {
int root;
struct Node {
int fa,son[],size,lmax,rmax,tot,
Max,val,lazy;
bool rev;
} Tree[MAXX+];
inline bool get(int x) {
return Tree[Tree[x].fa].son[] == x;
}
inline void build(int index,int l,int r) {
int id,mid;
mid = (l + r) >> ;
Tree[index].lazy = INF;
Tree[index].rev = ;
Tree[index].val = a[mid];
if (l == r) {
Tree[index].size = ;
Tree[index].lmax = Tree[index].rmax = Tree[index].Max = Tree[index].tot = a[mid];
return;
}
if (l < mid) {
id = stk.top();
stk.pop();
Tree[index].son[] = id;
Tree[id].fa = index;
build(id,l,mid-);
}
if (mid < r) {
id = stk.top();
stk.pop();
Tree[index].son[] = id;
Tree[id].fa = index;
build(id,mid+,r);
}
update(index);
}
inline void update(int index) {
if (!index) return;
Tree[index].tot = Tree[Tree[index].son[]].tot + Tree[Tree[index].son[]].tot + Tree[index].val;
Tree[index].size = Tree[Tree[index].son[]].size + Tree[Tree[index].son[]].size + ;
Tree[index].lmax = max(Tree[Tree[index].son[]].lmax,Tree[Tree[index].son[]].tot+max(Tree[Tree[index].son[]].lmax,)+Tree[index].val);
Tree[index].rmax = max(Tree[Tree[index].son[]].rmax,Tree[Tree[index].son[]].tot+max(Tree[Tree[index].son[]].rmax,)+Tree[index].val);
Tree[index].Max = max(Tree[Tree[index].son[]].Max,max(Tree[Tree[index].son[]].Max,Tree[index].val+max(Tree[Tree[index].son[]].rmax,)+max(Tree[Tree[index].son[]].lmax,)));
}
inline void pushdown(int index) {
int tmp;
if (Tree[index].lazy != INF) {
tmp = Tree[index].lazy;
Tree[index].lazy = INF;
if (Tree[index].son[]) Tree[Tree[index].son[]].tot = Tree[Tree[index].son[]].size * tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].tot = Tree[Tree[index].son[]].size * tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].val = tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].val = tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].lmax = Tree[Tree[index].son[]].rmax = Tree[Tree[index].son[]].Max = max(tmp,Tree[Tree[index].son[]].size*tmp);
if (Tree[index].son[]) Tree[Tree[index].son[]].lmax = Tree[Tree[index].son[]].rmax = Tree[Tree[index].son[]].Max = max(tmp,Tree[Tree[index].son[]].size*tmp);
if (Tree[index].son[]) Tree[Tree[index].son[]].lazy = tmp;
if (Tree[index].son[]) Tree[Tree[index].son[]].lazy = tmp;
}
if (Tree[index].rev) {
swap(Tree[index].son[],Tree[index].son[]);
swap(Tree[Tree[index].son[]].lmax,Tree[Tree[index].son[]].rmax);
swap(Tree[Tree[index].son[]].lmax,Tree[Tree[index].son[]].rmax);
Tree[Tree[index].son[]].rev ^= ;
Tree[Tree[index].son[]].rev ^= ;
Tree[index].rev = ;
}
}
inline int query_pos(int x) {
int index = root;
while (true) {
pushdown(index);
if (x > Tree[Tree[index].son[]].size) {
x -= Tree[Tree[index].son[]].size;
if (x == ) return index;
--x;
index = Tree[index].son[];
} else index = Tree[index].son[];
}
}
inline void clear(int index) {
Tree[Tree[index].fa].son[get(index)] = ;
Tree[index].fa = ;
stk.push(index);
if (Tree[index].son[]) clear(Tree[index].son[]);
if (Tree[index].son[]) clear(Tree[index].son[]);
}
inline void Insert(int index) {
int id;
int x = query_pos(index),
y = query_pos(index+);
splay(x,); splay(y,root);
id = stk.top();
stk.pop();
build(id,,tot);
Tree[Tree[root].son[]].son[] = id;
Tree[id].fa = Tree[root].son[];
update(Tree[root].son[]);
update(root);
}
inline void rotate(int x) {
int f = Tree[x].fa,g = Tree[f].fa,
tmpx = get(x),tmpf = get(f);
pushdown(f); pushdown(x);
if (!f) return;
Tree[f].son[tmpx] = Tree[x].son[tmpx^];
if (Tree[x].son[tmpx^]) Tree[Tree[x].son[tmpx^]].fa = f;
Tree[x].son[tmpx^] = f;
Tree[f].fa = x;
Tree[x].fa = g;
if (g) Tree[g].son[tmpf] = x;
update(f);
update(x);
}
inline void splay(int x,int pos) {
int f;
for (f = Tree[x].fa; (f = Tree[x].fa) != pos; rotate(x)) {
if (Tree[f].fa != pos)
rotate(get(f) == get(x) ? (f) : (x));
}
if (!pos) root = x;
}
inline void modify(int l,int r,int v) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
int tmp = Tree[Tree[root].son[]].son[];
Tree[tmp].val = Tree[tmp].lazy = v;
Tree[tmp].tot = v * Tree[tmp].size;
Tree[tmp].lmax = Tree[tmp].rmax = Tree[tmp].Max = max(Tree[tmp].size*v,v);
update(Tree[root].son[]);
update(root);
}
inline void reverse(int l,int r) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
Tree[Tree[Tree[root].son[]].son[]].rev ^= ;
swap(Tree[Tree[Tree[root].son[]].son[]].lmax,Tree[Tree[Tree[root].son[]].son[]].rmax);
}
inline void erase(int l,int r) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
clear(Tree[Tree[root].son[]].son[]);
Tree[Tree[root].son[]].son[] = ;
update(Tree[root].son[]);
update(root);
}
int get_sum(int l,int r) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
return Tree[Tree[Tree[root].son[]].son[]].tot;
}
int max_sum(int l,int r) {
int x = query_pos(l-),
y = query_pos(r+);
splay(x,); splay(y,root);
return Tree[Tree[Tree[root].son[]].son[]].Max;
}
} T; int main() { read(N); read(M); for (i = ; i <= MAXX; i++) stk.push(i); a[] = a[N+] = -INF;
for (i = ; i <= N + ; i++) read(a[i]); T.Tree[].lmax = T.Tree[].rmax = T.Tree[].Max = -INF;
T.root = ;
T.build(,,N+); while (M--) {
scanf("%s",&opt);
if (opt[] == 'I') {
read(pos); read(tot);
for (i = ; i <= tot; i++) read(a[i]);
T.Insert(pos+);
N += tot;
} else if (opt[] == 'D') {
read(pos); read(tot);
T.erase(pos+,pos+tot);
N -= tot;
} else if (opt[] == 'M' && opt[] == 'K') {
read(pos); read(tot); read(val);
T.modify(pos+,pos+tot,val);
} else if (opt[] == 'R') {
read(pos); read(tot);
T.reverse(pos+,pos+tot);
} else if (opt[] == 'G') {
read(pos); read(tot);
writeln(T.get_sum(pos+,pos+tot));
} else if (opt[] == 'M' && opt[] == 'X') {
writeln(T.max_sum(,N+));
}
} return ; }
【NOI 2005】 维修数列的更多相关文章
- NOI 2005 维修数列
妈妈呀我终于过了!!!原来是数据坑我!!! 弃疗弃疗弃疗弃疗!!!!我调了一天呢....被GET_SUM 8 0打败了.... 啥也不说了....还是我太年轻.... 更新了一下常数,跑的还是可以的: ...
- bzoj 1500 [NOI 2005] 维修数列
题目大意不多说了 貌似每个苦逼的acmer都要做一下这个splay树的模版题目吧 还是有很多操作的,估计够以后当模版了.... #include <cstdio> #include < ...
- NOI 2005维护数列
题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M, ...
- 洛谷 2042 BZOJ 1500 NOI 2005 维护数列
[题意概述] 维护一个数列,要求支持以下6种操作: [题解] 大Boss...可以用Treap解决 需要用到垃圾回收.线性建树. #include<cstdio> #include< ...
- 【BZOJ-1500】维修数列 Splay
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 11047 Solved: 3460[Submit][Statu ...
- [NOI2005] 维修数列
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 8397 Solved: 2530 Description In ...
- bzoj 1500: [NOI2005]维修数列 splay
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 6556 Solved: 1963[Submit][Status ...
- [BZOJ1500][NOI2005]维修数列---解题报告
Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...
- [BZOJ 1500]维修数列 [Splay Tree从进阶到住院]
历尽艰辛终于A掉了这题QwQ 贴COGS评论区几句话=.= 策爷:"splay/块状链表的自虐题.".深刻理解到如果没有M倾向就不要去写这题了.. -Chenyao2333 记得b ...
- 【BZOJ1500】【NOI2005】维修数列(Splay)
[BZOJ1500][NOI2005]维修数列(Splay) 题面 不想再看见这种毒瘤题,自己去BZOJ看 题解 Splay良心模板题 真的很简单 我一言不发 #include<iostream ...
随机推荐
- STL优先队列模板
1. 优先队列 用途:按照某一个关键字对插入元素或删除元素后的数据集进行自动排序 复杂度: logN 2. 数据声明 (1)头文件:#include<queue> (2)声明: prio ...
- T1013 求先序排列 codevs
http://codevs.cn/problem/1013/ 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Descr ...
- ELK之Elasticsearch、logstash部署及配置
ElasticSearch是一个搜索引擎,用来搜索.分析.存储日志; Logstash用来采集日志,把日志解析为json格式交给ElasticSearch; Kibana是一个数据可视化组件,把处理后 ...
- CODEVS 1245 最小的N个和 堆+排序
原题链接 http://codevs.cn/problem/1245/ 题目描述 Description 有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N^2 个和,求 ...
- Maven的相关问题(一)——settings.xml配置详解
工作中第一次正式接触maven,虽然之前在学习时有遇到过,但是对于maven的认识和理解确实太浅薄,仅仅局限于机械式的操,纸上得来终觉浅,绝知此事要躬行···古人诚不欺我也~ 下面先贴一个找到的一个非 ...
- TreeView 与 ListView
ListView: viewStyle icon 大图标 list 列表,单列 report 报表 smallIcon 小图标 largeImage 与icon对应 smallImage 与saml ...
- github/gitlab ssh-keys全局唯一
我们知道,通过在gitlab.github上设置ssh-key,可以直接拉取代码:git clone …… 公司为了代码安全,会对代码访问权限进行控制,不同人有不同代码的访问权限. 有时候,为了临时获 ...
- 自主学习Flappy Bird游戏
背景 强化学习 MDP基本元素 这部分比较难懂,没有详细看:最优函数值,最优控制等 Q-learning 神经网络 环境搭建 windows下通过pip安装TensorFlow,opencv-pyth ...
- Intent传递简单对象与集合
我们在Intent传递传递对象.能够有三种方式,实现Serializable接口.实现Parcelable接口,使用json格式序列化与反序列化. 在此我们使用第二方式,现实Parcelable接口, ...
- HDU 2845 Beans (两次线性dp)
Beans Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Subm ...