[学习笔记]可持久化数据结构 可持久化并查集

可持久化:支持查询历史版本和在历史版本上修改

可持久化数组

主席树做即可。

【模板】可持久化数组(可持久化线段树/平衡树)

可持久化并查集

可持久化并查集

主席树做即可。

要按秩合并。(路径压缩每次建logn条链,会卡爆空间MLE)

主席树节点,维护father(是一个真实下标),维护dep(集合的最大深度),

一个关键函数是query,找到代表实际位置为pos的节点的编号

对于一个版本,

合并:先找到这个两个位置的集合的根节点。

不在同一个集合里的话,就合并。

合并的时候,新建一条链,并且更新father,dep还是原来节点的dep

如果和连向的father的dep相同的话,那就把father的点的dep++,象征这个新连上的集合深度是最深深度。

(++deep的时候,可以不建立新节点。因为只是影响一些按秩合并效率,但是基本没有影响)

查询:直接查询即可。

【模板】可持久化并查集

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
#define mid ((l+r)>>1)
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=1e5+5;
struct node{
    int ls,rs;
    int fa,dep;
}t[N*40];
int tot;
int n,m;
int las;
int rt[2*N];
void build(int &x,int l,int r){
    x=++tot;
    if(l==r) {
        t[x].fa=l,t[x].dep=1;
        return ;
    }
    build(t[x].ls,l,mid);
    build(t[x].rs,mid+1,r);
}
int query(int x,int l,int r,int to){
    if(l==r) return x;
    if(to<=mid) return query(t[x].ls,l,mid,to);
    else return query(t[x].rs,mid+1,r,to);
}
void merge(int &x,int y,int l,int r,int to,int ff){
    x=++tot;
    t[x].ls=t[y].ls;t[x].rs=t[y].rs;
    if(l==r) {
        t[x].fa=ff,t[x].dep=t[y].dep;return;
    }
    if(to<=mid) merge(t[x].ls,t[y].ls,l,mid,to,ff);
    else merge(t[x].rs,t[y].rs,mid+1,r,to,ff);
}
int find(int o,int to){
//    cout<<" o "<<o<<" to "<<to<<endl;
    int now=query(rt[o],1,n,to);
    if(t[now].fa==to) return now;
    return find(o,t[now].fa);
}
int main(){
    scanf("%d%d",&n,&m);
    build(rt[0],1,n);
//    cout<<" tot tot tot "<<tot<<endl;
//        for(reg i=1;i<=tot;++i){
//            cout<<i<<" : "<<t[i].fa<<" "<<t[i].dep<<endl;
//        }
    int op,k,x,y;las=0;
    int o=0;
    while(m--){
        rd(op);
        if(op==1){
            ++o;
            rt[o]=rt[las];
            rd(x);rd(y);
            x=find(las,x);
            y=find(las,y);
            if(t[x].fa!=t[y].fa){
                if(t[x].dep>t[y].dep) swap(x,y);
                merge(rt[o],rt[las],1,n,t[x].fa,t[y].fa);
                if(t[x].dep==t[y].dep) {
                //    cout<<" dep equal "<<t[y].fa<<endl;
                    int lp=query(rt[o],1,n,t[y].fa);
                //    cout<<" lplplp "<<lp<<endl;
                    t[lp].dep++;
                }
            }
            las=o;
        }else if(op==2){
            ++o;
            rd(k);
            rt[o]=rt[k];
            las=k;
        }else{
            ++o;
            //cout<<" las "<<las<<endl;
            rt[o]=rt[las];
            rd(x);rd(y);
            //cout<<" x "<<" y "<<x<<" "<<y<<endl;
            x=find(las,x);
            y=find(las,y);
            //cout<<" xx "<<" yy "<<x<<" "<<y<<endl;
            if(t[x].fa==t[y].fa){
                puts("1");
            }else puts("0");
            las=o;
        }
//        cout<<" tot tot tot "<<tot<<endl;
//        for(reg i=1;i<=tot;++i){
//            cout<<i<<" : "<<t[i].fa<<" "<<t[i].dep<<endl;
//        }
    }
    return 0;
}

}
int main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/11/23 7:48:57
*/
可持久化并查集

可持久化平衡树:

1.还是主席树做即可。

权值暴力开到-1e9~1e9(我脑残了一下,还加了偏移量。。。)因为动态开点。。空间限制1GB

然后做就好了。

注意前驱后继的写法;

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define mid (((ll)l+r)>>1)
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=5e5+5;
const int U=2e9+1;
const int P=1e9+1;
const int inf=2147483647;
int n;
struct node{
    int ls,rs,sz;
}t[40*N];
int rt[N];
int tot;
void pushup(int x){
    t[x].sz=t[t[x].ls].sz+t[t[x].rs].sz;
}
void ins(int &x,int y,int l,int r,int to){
    //
    x=++tot;
    t[x].ls=t[y].ls,t[x].rs=t[y].rs;
    t[x].sz=t[y].sz+1;
    if(l==r) return;
    if(to<=mid) ins(t[x].ls,t[y].ls,l,mid,to);
    else ins(t[x].rs,t[y].rs,mid+1,r,to);
}
void dele(int &x,int y,int l,int r,int to){
//    cout<<" deleting "<<to<<endl;
    x=++tot;
    t[x].ls=t[y].ls,t[x].rs=t[y].rs;
    t[x].sz=t[y].sz;
    if(l==r){
        if(t[x].sz>=1) t[x].sz--;
        return;
    }
    if(to<=mid) dele(t[x].ls,t[y].ls,l,mid,to);
    else dele(t[x].rs,t[y].rs,mid+1,r,to);
    pushup(x);
}
int rk(int x,int l,int r,int c){
    if(l==r){
        return (l<c)*t[x].sz;
    }
    if(c<=mid) return rk(t[x].ls,l,mid,c);
    else return t[t[x].ls].sz+rk(t[x].rs,mid+1,r,c);
}
int kth(int x,int l,int r,int k){
    //cout<<l<<" "<<r<<" "<<mid<<" kkk "<<k<<" "<<t[x].sz<<endl;
    if(l==r)return l;
    int d=k-t[t[x].ls].sz;
    if(d<=0) return kth(t[x].ls,l,mid,k);
    else return kth(t[x].rs,mid+1,r,d);
}
int pre(int x,int l,int r,int c){
    if(l>=c||t[x].sz==0) return -inf;
    else if(l==r) return l;
    else{
        int ret=pre(t[x].rs,mid+1,r,c);
        if(ret!=-inf) return ret;
        return pre(t[x].ls,l,mid,c);
    }
}
int bac(int x,int l,int r,int c){
    //cout<<l<<" "<<r<<" "<<" : "<<t[x].sz<<endl;
    if(r<=c||t[x].sz==0) return inf;
    else if(l==r) return l;
    else{
        int ret=bac(t[x].ls,l,mid,c);
        if(ret!=inf) return ret;
        return bac(t[x].rs,mid+1,r,c);
    }
}
int main(){
    scanf("%d",&n);
    int st,op,x;
    int o=0;
    while(n--){
        rd(st),rd(op);rd(x);
        x+=P;
        ++o;
        rt[o]=rt[st];
        switch(op){
            case 1:ins(rt[o],rt[st],1,U,x);break;
            case 2:dele(rt[o],rt[st],1,U,x);break;
            case 3:printf("%d\n",rk(rt[o],1,U,x)+1);break;
            case 4:{
                int tmp=kth(rt[o],1,U,x-P);
                //cout<<" tmp "<<tmp<<" "<<tmp-1e9<<" "<<tmp-1e9-1<<endl;
                printf("%d\n",tmp-P);
                break;
            }
            case 5:{
                int tmp=pre(rt[o],1,U,x);
                if(tmp>=1&&tmp<=U){
                    printf("%d\n",tmp-P);
                }
                else printf("%d\n",tmp);//not find
                break;
            }
            case 6:{
                int tmp=bac(rt[o],1,U,x);
                if(tmp>=1&&tmp<=U){
                    printf("%d\n",tmp-P);
                }
                else printf("%d\n",tmp);//not find
                break;
            }
        }
        //cout<<" num "<<o<<" : "<<" tot "<<tot<<" sz "<<rt[o]<<" "<<t[rt[o]].sz<<endl;
    }
    return 0;
}

}
int main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/11/23 9:19:03
*/
可持久化平衡树

2.fhq-Treap?

留坑

可持久化0/1Trie

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/10006784.html