2019.01.14【洛谷P5055】可持久化文艺平衡树(可持久化FHQ_treap)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/86483031

传送门


解析:

不会有人真的试图去可持久化Splay吧。。。

你仔细研究一下就会发现Splay最坏情况下会把树中所有节点的父子关系全部打乱。。。两三次操作就新建 O ( n ) O(n) 个节点,于是你就RE或者MLE了。

当然你可以试一试朝鲜树可持久化,不过复杂度不够优秀。

于是这里请出优秀的FHQ_treap。

不持久化的话都是常规操作吧, 废话

可持久化还是比较简单的,我们只需要在下放标记的时候新建一波节点split的时候新建一波节点。

merge就不用新建了,因为merge出的链上都是split的链出来的节点,所以我们只需要在split的时候新建就行了。

当然空间常数十分不优秀就对了(不然你可以写 O ( n n ) O(n\sqrt n) 的朝鲜树(而且还不兹磁区间操作))。(逃


代码;

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define cs const

namespace IO{
    namespace IOONLY{
        cs int Rlen=1<<18|1;
        char buf[Rlen],*p1,*p2;
        char obuf[Rlen],*p3=obuf;
        char ch[23];
    }
    inline char get_char(){
        using namespace IOONLY;
        return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
    }
    inline void put_char(char c){
        using namespace IOONLY;
        *p3++=c;
        if(p3==obuf+Rlen)fwrite(obuf,1,Rlen,stdout),p3=obuf;
    }
    inline void FLUSH(){
        using namespace IOONLY;
        fwrite(obuf,1,p3-obuf,stdout),p3=obuf;
    }
    
    inline int getint(){
        re int num;
        re char c;
        re bool f=0;
        while(!isdigit(c=gc()))if(c=='-')f=1;num=c^48;
        while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
        return f?-num:num;
    }
    inline void outint(ll a){
        using namespace IOONLY;
        if(a==0)pc('0');
        if(a<0)pc('-'),a=-a;
        while(a)ch[++ch[0]]=a-a/10*10,a/=10;
        while(ch[0])pc(ch[ch[0]--]^48);
    }
}
using namespace IO;

cs int N=200005,B=120;
ll lasans;
namespace FHQ_treap{
    namespace Vars{
        int son[N*B][2];
        int siz[N*B];
        int val[N*B];
        ll sum[N*B];
        int pri[N*B];
        bool rev[N*B];
        int tot;
    }
    
    inline int newnode(int _val){
        using namespace Vars;
        int now=++tot;
        siz[now]=1;
        son[now][0]=son[now][1]=0;
        val[now]=_val;
        pri[now]=rand();
        rev[now]=0;
        sum[now]=_val;
        return now;
    }
    
    inline int copy_node(int _c){
        using namespace Vars;
        int now=++tot;
        siz[now]=siz[_c];
        son[now][0]=son[_c][0];
        son[now][1]=son[_c][1];
        val[now]=val[_c];
        pri[now]=pri[_c];
        rev[now]=rev[_c];
        sum[now]=sum[_c];
        return now;
    }
    
    inline void pushup(int now){
        using namespace Vars;
        siz[now]=siz[son[now][0]]+siz[son[now][1]]+1;
        sum[now]=sum[son[now][0]]+sum[son[now][1]]+val[now];
    }
    
    inline void pushdown(int now){
        using namespace Vars;
        if(rev[now]){
            if(son[now][0])son[now][0]=copy_node(son[now][0]);
            if(son[now][1])son[now][1]=copy_node(son[now][1]);
            swap(son[now][0],son[now][1]);
            if(son[now][0])rev[son[now][0]]^=1;
            if(son[now][1])rev[son[now][1]]^=1;
            rev[now]=0;
        }
    }
    
    pair<int,int> split_siz(int now,cs int &key){
        using namespace Vars;
        if(!now)return make_pair(0,0);
        pair<int,int> res;
        pushdown(now);
        now=copy_node(now);
        if(key<siz[son[now][0]]+1){
            res=split_siz(son[now][0],key);
            son[now][0]=res.second;
            res.second=now;
        }
        else {
            res=split_siz(son[now][1],key-siz[son[now][0]]-1);
            son[now][1]=res.first;
            res.first=now;
        }
        pushup(now);
        return res;
    }
    
    int merge(int lc,int rc){
        using namespace Vars;
        if(!lc||!rc)return lc+rc;
        pushdown(lc);
        pushdown(rc);
        if(pri[lc]>pri[rc]){
            son[lc][1]=merge(son[lc][1],rc);
            pushup(lc);
            return lc;
        }
        else {
            son[rc][0]=merge(lc,son[rc][0]);
            pushup(rc);
            return rc;
        }
    }
    
    inline int Insert(int now,int pos,int _val){
        using namespace Vars;
        pair<int,int> res=split_siz(now,pos);
        return merge(merge(res.first,newnode(_val)),res.second);
    }
    
    inline int Del(int now,int pos){
        using namespace Vars;
        pair<int,int> res1=split_siz(now,pos-1);
        pair<int,int> res2=split_siz(res1.second,1);
        return merge(res1.first,res2.second);
    }
    
    inline int rev_range(int now,int l,int r){
        using namespace Vars;
        pair<int,int> res1=split_siz(now,r);
        pair<int,int> res2=split_siz(res1.first,l-1);
        rev[res2.second]^=1;
        return merge(merge(res2.first,res2.second),res1.second);
    }
    
    inline int query_sum(int now,int l,int r){
        using namespace Vars;
        pair<int,int> res1=split_siz(now,r);
        pair<int,int> res2=split_siz(res1.first,l-1);
        outint(lasans=sum[res2.second]);pc('\n');
        return merge(merge(res2.first,res2.second),res1.second);
    }
    
}
using namespace FHQ_treap;

int n;
int rt[N];

signed main(){
    n=getint();
    for(int re i=1;i<=n;++i){
        int v=getint(),op=getint();
        switch(op){
            case 1:{
                int pos=getint()^lasans,_val=getint()^lasans;
                rt[i]=Insert(rt[v],pos,_val);
                break;
            }
            case 2:{
                int pos=getint()^lasans;
                rt[i]=Del(rt[v],pos);
                break;
            }
            case 3:{
                int l=getint()^lasans,r=getint()^lasans;
                rt[i]=rev_range(rt[v],l,r);
                break;
            }
            case 4:{
                int l=getint()^lasans,r=getint()^lasans;
                rt[i]=query_sum(rt[v],l,r);
                break;
            }
        }
    }
    FLUSH();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/86483031