洛谷p5055【模板】可持久化文藝平衡樹
阿新 • • 發佈:2019-03-05
關於 clone tex mat clas long long pri rand() out 下來,自然我們就需要一個\(\text{clone}\)函數來完成這個步驟,我們遞歸的時候直接改掉這顆克隆節點的左右孩子就好了。
至於\(\text{merge}\)由於我們在\(\text{split}\)的時候已經克隆過了,我們只需要安心大膽的合並即可。
還有一個關於空間的問題。
當我們每次刪除一個節點時,這個位置的資源就空了出來。如果不使用的話就實在太浪費了。
我們用一個\(\text{emp}\)數組來完成這個操作。
好像十分好寫的樣子。
可持久化\(\text{fhq-treap}\)。
比較常用的平衡樹一般就是\(\text{fhq-treap}\)和\(\text{splay}\)了,因為\(\text{splay}\)在旋轉的時候樹的形態發生了變換,固不能進行可持久化。而\(\text{fhq-treap}\)的所有操作都是基於分裂和合並的基礎上的,對這棵樹並沒有影響,故可以進行可持久化。
如何進行可持久化?
我們先思考一下一顆普通的\(\text{fhq-treap}\)怎麽寫?
我們用\(\text{size}\)在分的時候一般直接讓當前節點的左/右孩子直接進行遞歸。然而我們在可持久化的時候必須要將要求的歷史版本的樹全部\(\text{copy}\)
至於\(\text{merge}\)由於我們在\(\text{split}\)的時候已經克隆過了,我們只需要安心大膽的合並即可。
還有一個關於空間的問題。
當我們每次刪除一個節點時,這個位置的資源就空了出來。如果不使用的話就實在太浪費了。
我們用一個\(\text{emp}\)數組來完成這個操作。
好像十分好寫的樣子。
My Code:
#include <bits/stdc++.h> #define il inline typedef long long ll; const int maxn = 2e5 + 10; using namespace std; template<class T> il void rd(T& res) { res = 0;char c;bool sign = 0; for(c = getchar();!isdigit(c);c = getchar()) sign |= c == '-'; for(;isdigit(c);c = getchar()) res = (res << 1) + (res << 3) + (c ^ 48); (sign) && (res = -res); return; } struct TreapNode { int ch[2]; int rnd,size,val;bool rev; ll sum; }tr[maxn << 6]; int emp[maxn],root[maxn]; int n,m,i,j,k,q,tot,emp_top,a,b,c,d;ll lans; il void _swap(int& x,int& y) { x ^= y ^= x ^= y; return; } il int new_node(int v) { int id = emp_top ? emp[emp_top--] : ++tot; tr[id].rnd = rand();tr[id].val = v; tr[id].size = 1;tr[id].sum = v;tr[id].rev = 0; tr[id].ch[0] = tr[id].ch[1] = 0; return id; } il int clone(int o) { int id = emp_top ? emp[emp_top--] : ++tot; tr[id].ch[0] = tr[o].ch[0];tr[id].ch[1] = tr[o].ch[1]; tr[id].rnd = tr[o].rnd;tr[id].size = tr[o].size;tr[id].val = tr[o].val; tr[id].rev = tr[o].rev;tr[id].sum = tr[o].sum; return id; } il void push_down(int o) { if(tr[o].rev) { _swap(tr[o].ch[0],tr[o].ch[1]); if(tr[o].ch[0]) tr[o].ch[0] = clone(tr[o].ch[0]),tr[tr[o].ch[0]].rev ^= 1; if(tr[o].ch[1]) tr[o].ch[1] = clone(tr[o].ch[1]),tr[tr[o].ch[1]].rev ^= 1; tr[o].rev = 0; } return; } il void push_up(int o) { tr[o].size = tr[tr[o].ch[0]].size + tr[tr[o].ch[1]].size + 1; tr[o].sum = tr[tr[o].ch[0]].sum + tr[tr[o].ch[1]].sum + tr[o].val; return; } void split_k(int now,int k,int& x,int& y) { if(!now) {x = y = 0;return;} push_down(now); if(tr[tr[now].ch[0]].size < k) { x = clone(now); split_k(tr[x].ch[1],k - tr[tr[x].ch[0]].size - 1,tr[x].ch[1],y); push_up(x); } else { y = clone(now); split_k(tr[y].ch[0],k,x,tr[y].ch[0]); push_up(y); } return; } int merge(int u,int v) { if(!u) return v;if(!v) return u; if(tr[u].rnd < tr[v].rnd) { push_down(u); tr[u].ch[1] = merge(tr[u].ch[1],v); push_up(u); return u; } else { push_down(v); tr[v].ch[0] = merge(u,tr[v].ch[0]); push_up(v); return v; } } il void insert(int& root,int x,int v) { split_k(root,x,a,b); root = merge(merge(a,new_node(v)),b); return; } il void erase(int& root,int x) { split_k(root,x,a,c); split_k(a,x - 1,a,b); emp[++emp_top] = b; root = merge(a,c); return; } il void rever(int& root,int l,int r) { split_k(root,l - 1,a,b); split_k(b,r - l + 1,b,c); tr[b].rev ^= 1; root = merge(a,merge(b,c)); return; } il ll query(int& root,int l,int r) { split_k(root,l - 1,a,b); split_k(b,r - l + 1,b,c); ll res = tr[b].sum; root = merge(a,merge(b,c)); return res; } int main() { srand((unsigned)time(NULL)); rd(q); for(int i = 1,x,y,l,r;i <= q;i++) { int his,opt;rd(his);rd(opt);root[i] = root[his]; switch(opt) { case 1:rd(x);rd(y);insert(root[i],x ^ lans,y ^ lans);break; case 2:rd(x);erase(root[i],x ^ lans);break; case 3:rd(l);rd(r);rever(root[i],l ^ lans,r ^ lans);break; case 4:rd(l);rd(r);l ^= lans;r ^= lans;printf("%lld\n",lans = query(root[i],l,r));break; } // cout << a << ' ' << b << ' ' << c << endl; } }
洛谷p5055【模板】可持久化文藝平衡樹