洛谷p5055【模板】可持久化文艺平衡树

可持久化\(\text{fhq-treap}\)
比较常用的平衡树一般就是\(\text{fhq-treap}\)\(\text{splay}\)了,因为\(\text{splay}\)在旋转的时候树的形态发生了变换,固不能进行可持久化。而\(\text{fhq-treap}\)的所有操作都是基于分裂和合并的基础上的,对这棵树并没有影响,故可以进行可持久化。

如何进行可持久化?

我们先思考一下一颗普通的\(\text{fhq-treap}\)怎么写?
我们用\(\text{size}\)在分的时候一般直接让当前节点的左/右孩子直接进行递归。然而我们在可持久化的时候必须要将要求的历史版本的树全部\(\text{copy}\)下来,自然我们就需要一个\(\text{clone}\)函数来完成这个步骤,我们递归的时候直接改掉这颗克隆节点的左右孩子就好了。
至于\(\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;
    }
} 

猜你喜欢

转载自www.cnblogs.com/Sai0511/p/10478711.html
今日推荐