【模板】可持久化数据结构

可持久化数组

洛咕

题意:如题,你需要维护这样的一个长度为N的数组,支持如下几种操作:

1 在某个历史版本上修改某一个位置上的值

2 访问某个历史版本上的某一位置的值

此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本.版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组).

const int N=1e6+5;
int tot,a[N],root[N];
struct ZXS{
    int ls[N*30],rs[N*30],val[N*30];
    inline int build(int l,int r){
        int i=++tot;
        if(l==r){val[i]=a[l];return i;}
        int mid=(l+r)>>1;
        ls[i]=build(l,mid);rs[i]=build(mid+1,r);
        return i;
    }
    inline int change(int p,int l,int r,int x,int d){
        int i=++tot;
        if(l==r){val[i]=d;return i;}
        ls[i]=ls[p];rs[i]=rs[p];
        int mid=(l+r)>>1;
        if(x<=mid)ls[i]=change(ls[p],l,mid,x,d);
        else rs[i]=change(rs[p],mid+1,r,x,d);
        return i;
    }
    inline int ask(int p,int l,int r,int x){
        if(l==r)return val[p];
        int mid=(l+r)>>1;
        if(x<=mid)return ask(ls[p],l,mid,x);
        else return ask(rs[p],mid+1,r,x);
    }
}T;
int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    root[0]=T.build(1,n);
    for(int i=1;i<=m;i++){
        int id=read(),opt=read(),pos=read();
        if(opt==1)root[i]=T.change(root[id],1,n,pos,read());
        else root[i]=root[id],printf("%d\n",T.ask(root[id],1,n,pos));
    }
    return 0;
}

可持久化线段树(主席树)

题意:给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值.

const int N=2e5+5;
int tot,root[N],b[N];
struct ppx{
    int val,id;
    inline bool operator <(ppx x){return val<x.val;}
}a[N];
struct PPX{
    int ls[N*30],rs[N*30],data[N*30];
    inline int build(int l,int r){
        int i=++tot;
        if(l==r)return i;
        int mid=(l+r)>>1;
        ls[i]=build(l,mid);rs[i]=build(mid+1,r);
        return i;
    }
    inline int add(int p,int l,int r,int x,int d){
        int i=++tot;ls[i]=ls[p];rs[i]=rs[p];
        if(l==r){data[i]+=d;return i;}
        int mid=(l+r)>>1;
        if(x<=mid)ls[i]=add(ls[p],l,mid,x,d);
        else rs[i]=add(rs[p],mid+1,r,x,d);
        data[i]=data[ls[i]]+data[rs[i]];
        return i;
    }
    inline int ask(int i,int j,int l,int r,int k){
        if(l==r)return a[l].val;
        int mid=(l+r)>>1,num=data[ls[j]]-data[ls[i]];
        if(k<=num)return ask(ls[i],ls[j],l,mid,k);
        else return ask(rs[i],rs[j],mid+1,r,k-num);
    }
}T;
int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;i++)a[i].val=read(),a[i].id=i;
    sort(a+1,a+n+1);for(int i=1;i<=n;i++)b[a[i].id]=i;
    root[0]=T.build(1,n);
    for(int i=1;i<=n;i++)root[i]=T.add(root[i-1],1,n,b[i],1);
    for(int i=1;i<=m;i++){
        int l=read()-1,r=read(),k=read();
        printf("%d\n",T.ask(root[l],root[r],1,n,k));
    }
    return 0;
}

可持久化并查集

题意:n个集合,m个操作.

操作1:合并a,b所在集合;

操作2:回到第k次操作之后的状态(查询也算作操作);

操作3:询问a,b是否属于同一集合;

const int N=200005;
int n,m,tot,root[N];
struct ppx{
    int ls[N*30],rs[N*30],deep[N*30],fa[N*30];
    inline int build(int l,int r){
        int i=++tot;
        if(l==r){fa[i]=l;deep[i]=1;return i;}
        int mid=(l+r)>>1;
        ls[i]=build(l,mid);rs[i]=build(mid+1,r);
        return i;
    }
    inline int add(int p,int l,int r,int x,int d){
        int i=++tot;
        if(l==r){fa[i]=d;return i;}
        int mid=(l+r)>>1;ls[i]=ls[p];rs[i]=rs[p];
        if(x<=mid)ls[i]=add(ls[p],l,mid,x,d);
        else rs[i]=add(rs[p],mid+1,r,x,d);
        return i;
    }
    inline int ask(int p,int l,int r,int x){
        if(l==r)return p;
        int mid=(l+r)>>1;
        if(x<=mid)return ask(ls[p],l,mid,x);
        else return ask(rs[p],mid+1,r,x);
    }
    inline int get(int p,int x){
        int ff=ask(p,1,n,x);
        if(x==fa[ff])return ff;
        return get(p,fa[ff]);
    }
}T;
int main(){
    n=read(),m=read();
    root[0]=T.build(1,n);
    for(int i=1;i<=m;i++){
        int opt=read();
        if(opt==1){
            int x=T.get(root[i-1],read());
            int y=T.get(root[i-1],read());
            if(T.deep[x]>=T.deep[y]){
            T.deep[x]=max(T.deep[x],T.deep[y]+1);
            root[i]=T.add(root[i-1],1,n,T.fa[y],T.fa[x]);
            }
            else root[i]=T.add(root[i-1],1,n,T.fa[x],T.fa[y]);
        }
        else if(opt==2)root[i]=root[read()];
        else{
            root[i]=root[i-1];
            int x=T.fa[T.get(root[i-1],read())];
            int y=T.fa[T.get(root[i-1],read())];
            printf("%d\n",x==y);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/PPXppx/p/10700082.html