zoukankan      html  css  js  c++  java
  • 【模板】可持久化数据结构

    可持久化数组

    洛咕

    题意:如题,你需要维护这样的一个长度为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
    ",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
    ",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
    ",x==y);
    		}
        }
        return 0;
    }
    
    
  • 相关阅读:
    【二次开发】shopxo商城
    经典的PHPer为什么被认为是草根?
    PowerDesigner生成Access数据库
    NET开发学习项目资源
    ASP.NET程序开发范例宝典
    Web.Config文件配置小记
    NET开发学习项目资源(2)
    VS 2010一步步开发windows服务(windows service)
    jquery.mobile手机网页简要
    Android置底一个View后运行报错
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10700082.html
Copyright © 2011-2022 走看看