BZOJ1500 : [NOI2005]维修数列-fhq_Treap
反正是道平衡树,就拿 fhq_Treap 写了写...
这道题思路基本是围绕“用 Treap 维护中序遍历” 和 中序遍历的性质 来进行的操作
所以就可以类比线段树进行一些操作
1. 建树 & 插入
这题也要用到笛卡尔树的建树方式,假的 O(n) 真是相当快啊
inline int build(int r) { top = 0; register int tmp = newnode(a[1]); stk[++top] = tmp; for(int i = 2; i <= r; ++i) { int last = 0, cur = newnode(a[i]); while(top and t[stk[top]].prio > t[cur].prio) { pushup(stk[top]); last = stk[top]; stk[top--] = 0; } t[cur].ch[0] = last; pushup(cur); if(top) { t[stk[top]].ch[1] = cur; pushup(stk[top]); } stk[++top] = cur; } while(top) pushup(stk[top--]); return stk[1]; }
在本题中呢,由于插入的值不是一个一个给出的而是给出序列,故应先建出一棵小 Treap 再合并过去
在这里也要用到上面提到的方式来建这棵小树
inline void Insert(int pos, int tot) { int newrt = build(tot); pair<int, int> x = Split(Root, pos); Root = Merge(Merge(x.first, newrt), x.second); return; }
2.删除
此题的删除也是删除一段序列,直接 Split 出来即可
不过这里注意到任何时刻数列中最多含有 5e5 个数,多写一个内存回收就好了
inline int Malloc(){ register int x; return (!delpool.empty()) ? (t[x = delpool.front()].clear(), delpool.pop(), x) : (++poolcur); } inline int newnode(int val) { register int cur = Malloc(); t[cur].val = t[cur].sum = t[cur].prtmx = val; t[cur].lmx = t[cur].rmx = max(0, val); t[cur].prio = rand(); t[cur].siz = 1; return cur; } void Recycle(int cur) { if(!cur) return; if(lson) Recycle(lson); delpool.push(cur); if(rson) Recycle(rson); return; } inline void Remove(int pos, int tot) { pair<int, int> x = Split(Root, pos + tot - 1); pair<int, int> y = Split(x.first, pos - 1); Recycle(y.second); Root = Merge(y.first, x.second); return; }
觉得递归不优美的可以手写栈模拟
3.区间修改
打标记
inline void cover(int pos, int tot, int val) { pair<int, int> x = Split(Root, pos + tot - 1); pair<int, int> y = Split(x.first, pos - 1); t[y.second].val = t[y.second].cvr = val; t[y.second].sum = val * t[y.second].siz; t[y.second].lmx = t[y.second].rmx = max(0, t[y.second].sum); t[y.second].prtmx = max(t[y.second].val, t[y.second].sum); t[y.second].rvrs = false; Root = Merge(Merge(y.first, y.second), x.second); return; }
4.翻转区间
比较基础的操作
inline void Reverse(int pos, int tot) { pair<int, int> x = Split(Root, pos + tot - 1); pair<int, int> y = Split(x.first, pos - 1); t[y.second].rvrs ^= 1; swap(t[y.second].lmx, t[y.second].rmx); swap(t[y.second].ch[0], t[y.second].ch[1]); Root = Merge(Merge(y.first, y.second), x.second); return; }
5.求和 & 最大子段和
这里一开始不敢这么写,其实是可以的
在提取一个区间的过程中,是在不断 pushup 和 pushdown 的,故提取/合并后并不会出什么差错
像线段树一样维护,一些维护的的值在 Reverse 后注意更新
inline void rvrs(int cur) { swap(lson, rson); swap(t[cur].lmx, t[cur].rmx); t[cur].rvrs ^= 1; return; } inline void cvr(int cur, int val) { t[cur].cvr = t[cur].val = val; t[cur].sum = t[cur].siz * val; t[cur].prtmx = max(t[cur].val, t[cur].sum); t[cur].lmx = t[cur].rmx = max(0, t[cur].sum); return; } inline void pushup(int cur) { t[cur].siz = t[lson].siz + t[rson].siz + 1; t[cur].sum = t[cur].val + t[lson].sum + t[rson].sum; t[cur].lmx = max(0, max(t[lson].lmx, t[lson].sum + t[rson].lmx + t[cur].val)); t[cur].rmx = max(0, max(t[rson].rmx, t[rson].sum + t[lson].rmx + t[cur].val)); t[cur].prtmx = max(t[cur].val, t[lson].rmx + t[rson].lmx + t[cur].val); if(lson) t[cur].prtmx = max(t[cur].prtmx, t[lson].prtmx); if(rson) t[cur].prtmx = max(t[cur].prtmx, t[rson].prtmx); return; } inline void pushdown(int cur) { if(t[cur].rvrs) { if(lson) rvrs(lson); if(rson) rvrs(rson); } if(t[cur].cvr != inf) { if(lson) cvr(lson, t[cur].cvr); if(rson) cvr(rson, t[cur].cvr); } t[cur].rvrs = false; t[cur].cvr = inf; return; }
完整的代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cctype> #include<cstdio> #include<cmath> #include<queue> #include<ctime> #define lson t[cur].ch[0] #define rson t[cur].ch[1] using namespace std; const int MAXN = 500010, inf = 2333; struct Node{ int ch[2], siz, val, prio, lmx, rmx, sum, prtmx; int cvr; bool rvrs; Node(){ch[0] = ch[1] = siz = val = sum = 0; cvr = inf; rvrs = false;} void clear(){ ch[0] = ch[1] = siz = val = sum = 0; cvr = inf; rvrs = false; return; } }t[MAXN]; int n, m, poolcur, Root; int a[MAXN], stk[MAXN], top; queue<int> delpool; char que[20]; inline int Malloc(){ register int x; return (!delpool.empty()) ? (t[x = delpool.front()].clear(), delpool.pop(), x) : (++poolcur); } inline int newnode(int val) { register int cur = Malloc(); t[cur].val = t[cur].sum = t[cur].prtmx = val; t[cur].lmx = t[cur].rmx = max(0, val); t[cur].prio = rand(); t[cur].siz = 1; return cur; } inline void pushup(int cur) { t[cur].siz = t[lson].siz + t[rson].siz + 1; t[cur].sum = t[cur].val + t[lson].sum + t[rson].sum; t[cur].lmx = max(0, max(t[lson].lmx, t[lson].sum + t[rson].lmx + t[cur].val)); t[cur].rmx = max(0, max(t[rson].rmx, t[rson].sum + t[lson].rmx + t[cur].val)); t[cur].prtmx = max(t[cur].val, t[lson].rmx + t[rson].lmx + t[cur].val); if(lson) t[cur].prtmx = max(t[cur].prtmx, t[lson].prtmx); if(rson) t[cur].prtmx = max(t[cur].prtmx, t[rson].prtmx); return; } inline void rvrs(int cur) { swap(lson, rson); swap(t[cur].lmx, t[cur].rmx); t[cur].rvrs ^= 1; return; } inline void cvr(int cur, int val) { t[cur].cvr = t[cur].val = val; t[cur].sum = t[cur].siz * val; t[cur].prtmx = max(t[cur].val, t[cur].sum); t[cur].lmx = t[cur].rmx = max(0, t[cur].sum); return; } inline void pushdown(int cur) { if(t[cur].rvrs) { if(lson) rvrs(lson); if(rson) rvrs(rson); } if(t[cur].cvr != inf) { if(lson) cvr(lson, t[cur].cvr); if(rson) cvr(rson, t[cur].cvr); } t[cur].rvrs = false; t[cur].cvr = inf; return; } inline int build(int r) { top = 0; register int tmp = newnode(a[1]); stk[++top] = tmp; for(int i = 2; i <= r; ++i) { int last = 0, cur = newnode(a[i]); while(top and t[stk[top]].prio > t[cur].prio) { pushup(stk[top]); last = stk[top]; stk[top--] = 0; } t[cur].ch[0] = last; pushup(cur); if(top) { t[stk[top]].ch[1] = cur; pushup(stk[top]); } stk[++top] = cur; } while(top) pushup(stk[top--]); return stk[1]; } pair<int, int> Split(int cur, int k) { if(!cur or !k) return make_pair(0, cur); pushdown(cur); pair<int, int> res; if(t[lson].siz >= k) { res = Split(lson, k); lson = res.second; pushup(cur); res.second = cur; } else { res = Split(rson, k - t[lson].siz - 1); rson = res.first; pushup(cur); res.first = cur; } return res; } int Merge(int x, int y) { if(x) pushdown(x); if(y) pushdown(y); if(!x) return y; if(!y) return x; if(t[x].prio < t[y].prio) { t[x].ch[1] = Merge(t[x].ch[1], y); pushup(x); return x; } else { t[y].ch[0] = Merge(x, t[y].ch[0]); pushup(y); return y; } } void Recycle(int cur) { if(!cur) return; if(lson) Recycle(lson); delpool.push(cur); if(rson) Recycle(rson); return; } inline void Insert(int pos, int tot) { int newrt = build(tot); pair<int, int> x = Split(Root, pos); Root = Merge(Merge(x.first, newrt), x.second); return; } inline void Remove(int pos, int tot) { pair<int, int> x = Split(Root, pos + tot - 1); pair<int, int> y = Split(x.first, pos - 1); Recycle(y.second); Root = Merge(y.first, x.second); return; } inline void Reverse(int pos, int tot) { pair<int, int> x = Split(Root, pos + tot - 1); pair<int, int> y = Split(x.first, pos - 1); t[y.second].rvrs ^= 1; swap(t[y.second].lmx, t[y.second].rmx); swap(t[y.second].ch[0], t[y.second].ch[1]); Root = Merge(Merge(y.first, y.second), x.second); return; } inline void cover(int pos, int tot, int val) { pair<int, int> x = Split(Root, pos + tot - 1); pair<int, int> y = Split(x.first, pos - 1); t[y.second].val = t[y.second].cvr = val; t[y.second].sum = val * t[y.second].siz; t[y.second].lmx = t[y.second].rmx = max(0, t[y.second].sum); t[y.second].prtmx = max(t[y.second].val, t[y.second].sum); t[y.second].rvrs = false; Root = Merge(Merge(y.first, y.second), x.second); return; } inline int getsum(int pos, int tot) { pair<int, int> x = Split(Root, pos + tot - 1); pair<int, int> y = Split(x.first, pos - 1); int ans = t[y.second].sum; Root = Merge(Merge(y.first, y.second), x.second); return ans; } void rdstr(char s[]) { register int sz = 0; register char c = getchar(); while(!isalpha(c) and c != '-') c = getchar(); while(isalpha(c) || (c == '-')) { s[sz++] = c; c = getchar(); } return; } inline int rd() { register int x = 0; register char c = getchar(); register bool f = false; while(!isdigit(c)) { if(c == '-') f = true; c = getchar(); } while(isdigit(c)) { x = x * 10 + (c ^ 48); c = getchar(); } return f ? -x : x; } int main() { srand(time(NULL)); n = rd(); m = rd(); for(int i = 1; i <= n; ++i) a[i] = rd(); Root = build(n); int pos, tot, val; while(m--) { rdstr(que); switch(que[0]) { case 'I':{ pos = rd(); tot = rd(); for(int i = 1; i <= tot; ++i) a[i] = rd(); Insert(pos, tot); break; } case 'D':{ pos = rd(); tot = rd(); Remove(pos, tot); break; } case 'R':{ pos = rd(); tot = rd(); Reverse(pos, tot); break; } case 'G':{ pos = rd(); tot = rd(); printf("%d\n", getsum(pos, tot)); break; } case 'M':{ if(que[2] == 'K') { pos = rd(); tot = rd(); val = rd(); cover(pos, tot, val); } else { printf("%d\n", t[Root].prtmx); } break; } } } return 0; }
禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载
,用户转载请注明出处:https://www.cnblogs.com/xcysblog/