【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+10]; char opt[10]; stack<int> stk; template <typename T> inline void read(T &x) { int f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) { if (c == '-') f = -f; } for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> inline void write(T x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) write(x/10); putchar(x%10+'0'); } template <typename T> inline void writeln(T x) { write(x); puts(""); } struct Splay { int root; struct Node { int fa,son[2],size,lmax,rmax,tot, Max,val,lazy; bool rev; } Tree[MAXX+10]; inline bool get(int x) { return Tree[Tree[x].fa].son[1] == x; } inline void build(int index,int l,int r) { int id,mid; mid = (l + r) >> 1; Tree[index].lazy = INF; Tree[index].rev = 0; Tree[index].val = a[mid]; if (l == r) { Tree[index].size = 1; 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[0] = id; Tree[id].fa = index; build(id,l,mid-1); } if (mid < r) { id = stk.top(); stk.pop(); Tree[index].son[1] = id; Tree[id].fa = index; build(id,mid+1,r); } update(index); } inline void update(int index) { if (!index) return; Tree[index].tot = Tree[Tree[index].son[0]].tot + Tree[Tree[index].son[1]].tot + Tree[index].val; Tree[index].size = Tree[Tree[index].son[0]].size + Tree[Tree[index].son[1]].size + 1; Tree[index].lmax = max(Tree[Tree[index].son[0]].lmax,Tree[Tree[index].son[0]].tot+max(Tree[Tree[index].son[1]].lmax,0)+Tree[index].val); Tree[index].rmax = max(Tree[Tree[index].son[1]].rmax,Tree[Tree[index].son[1]].tot+max(Tree[Tree[index].son[0]].rmax,0)+Tree[index].val); Tree[index].Max = max(Tree[Tree[index].son[0]].Max,max(Tree[Tree[index].son[1]].Max,Tree[index].val+max(Tree[Tree[index].son[0]].rmax,0)+max(Tree[Tree[index].son[1]].lmax,0))); } inline void pushdown(int index) { int tmp; if (Tree[index].lazy != INF) { tmp = Tree[index].lazy; Tree[index].lazy = INF; if (Tree[index].son[0]) Tree[Tree[index].son[0]].tot = Tree[Tree[index].son[0]].size * tmp; if (Tree[index].son[1]) Tree[Tree[index].son[1]].tot = Tree[Tree[index].son[1]].size * tmp; if (Tree[index].son[0]) Tree[Tree[index].son[0]].val = tmp; if (Tree[index].son[1]) Tree[Tree[index].son[1]].val = tmp; if (Tree[index].son[0]) Tree[Tree[index].son[0]].lmax = Tree[Tree[index].son[0]].rmax = Tree[Tree[index].son[0]].Max = max(tmp,Tree[Tree[index].son[0]].size*tmp); if (Tree[index].son[1]) Tree[Tree[index].son[1]].lmax = Tree[Tree[index].son[1]].rmax = Tree[Tree[index].son[1]].Max = max(tmp,Tree[Tree[index].son[1]].size*tmp); if (Tree[index].son[0]) Tree[Tree[index].son[0]].lazy = tmp; if (Tree[index].son[1]) Tree[Tree[index].son[1]].lazy = tmp; } if (Tree[index].rev) { swap(Tree[index].son[0],Tree[index].son[1]); swap(Tree[Tree[index].son[0]].lmax,Tree[Tree[index].son[0]].rmax); swap(Tree[Tree[index].son[1]].lmax,Tree[Tree[index].son[1]].rmax); Tree[Tree[index].son[0]].rev ^= 1; Tree[Tree[index].son[1]].rev ^= 1; Tree[index].rev = 0; } } inline int query_pos(int x) { int index = root; while (true) { pushdown(index); if (x > Tree[Tree[index].son[0]].size) { x -= Tree[Tree[index].son[0]].size; if (x == 1) return index; --x; index = Tree[index].son[1]; } else index = Tree[index].son[0]; } } inline void clear(int index) { Tree[Tree[index].fa].son[get(index)] = 0; Tree[index].fa = 0; stk.push(index); if (Tree[index].son[0]) clear(Tree[index].son[0]); if (Tree[index].son[1]) clear(Tree[index].son[1]); } inline void Insert(int index) { int id; int x = query_pos(index), y = query_pos(index+1); splay(x,0); splay(y,root); id = stk.top(); stk.pop(); build(id,1,tot); Tree[Tree[root].son[1]].son[0] = id; Tree[id].fa = Tree[root].son[1]; update(Tree[root].son[1]); 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^1]; if (Tree[x].son[tmpx^1]) Tree[Tree[x].son[tmpx^1]].fa = f; Tree[x].son[tmpx^1] = 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-1), y = query_pos(r+1); splay(x,0); splay(y,root); int tmp = Tree[Tree[root].son[1]].son[0]; 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[1]); update(root); } inline void reverse(int l,int r) { int x = query_pos(l-1), y = query_pos(r+1); splay(x,0); splay(y,root); Tree[Tree[Tree[root].son[1]].son[0]].rev ^= 1; swap(Tree[Tree[Tree[root].son[1]].son[0]].lmax,Tree[Tree[Tree[root].son[1]].son[0]].rmax); } inline void erase(int l,int r) { int x = query_pos(l-1), y = query_pos(r+1); splay(x,0); splay(y,root); clear(Tree[Tree[root].son[1]].son[0]); Tree[Tree[root].son[1]].son[0] = 0; update(Tree[root].son[1]); update(root); } int get_sum(int l,int r) { int x = query_pos(l-1), y = query_pos(r+1); splay(x,0); splay(y,root); return Tree[Tree[Tree[root].son[1]].son[0]].tot; } int max_sum(int l,int r) { int x = query_pos(l-1), y = query_pos(r+1); splay(x,0); splay(y,root); return Tree[Tree[Tree[root].son[1]].son[0]].Max; } } T; int main() { read(N); read(M); for (i = 2; i <= MAXX; i++) stk.push(i); a[1] = a[N+2] = -INF; for (i = 2; i <= N + 1; i++) read(a[i]); T.Tree[0].lmax = T.Tree[0].rmax = T.Tree[0].Max = -INF; T.root = 1; T.build(1,1,N+2); while (M--) { scanf("%s",&opt); if (opt[0] == 'I') { read(pos); read(tot); for (i = 1; i <= tot; i++) read(a[i]); T.Insert(pos+1); N += tot; } else if (opt[0] == 'D') { read(pos); read(tot); T.erase(pos+1,pos+tot); N -= tot; } else if (opt[0] == 'M' && opt[2] == 'K') { read(pos); read(tot); read(val); T.modify(pos+1,pos+tot,val); } else if (opt[0] == 'R') { read(pos); read(tot); T.reverse(pos+1,pos+tot); } else if (opt[0] == 'G') { read(pos); read(tot); writeln(T.get_sum(pos+1,pos+tot)); } else if (opt[0] == 'M' && opt[2] == 'X') { writeln(T.max_sum(2,N+1)); } } return 0; }