推荐博客:
可持久化数组:https://blog.csdn.net/chenxiaoran666/article/details/81503323
可持久化并查集:https://blog.csdn.net/chenxiaoran666/article/details/81505870
https://www.cnblogs.com/peng-ym/p/9357220.html
模板:
1,可持久化数组
luogu3919:https://www.luogu.org/problem/P3919
题意:有一个数列,支持在原来的某一版本查询位置为$loc$的值;修改某一版本位置为$loc$的值为$xx$。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e6+10; 4 struct node{ 5 int l,r; int val; 6 }tree[maxn*100]; 7 int root[maxn],a[maxn],sz=0; 8 void build(int &x,int l,int r){ 9 x=++sz; 10 if (l==r){ 11 tree[x].val=a[l]; 12 return ; 13 } 14 int mid=(l+r)>>1; 15 build(tree[x].l,l,mid); 16 build(tree[x].r,mid+1,r); 17 } 18 void update(int &x,int y,int l,int r,int dex,int val){ 19 x=++sz; tree[x]=tree[y]; 20 if (l==r){ 21 tree[x].val=val; 22 return ; 23 } 24 int mid=(l+r)>>1; 25 if (dex<=mid) update(tree[x].l,tree[y].l,l,mid,dex,val); 26 else update(tree[x].r,tree[y].r,mid+1,r,dex,val); 27 } 28 int query(int x,int l,int r,int xx){ 29 if (l==r) return tree[x].val; 30 int mid=(l+r)>>1; 31 if (xx<=mid) return query(tree[x].l,l,mid,xx); 32 else return query(tree[x].r,mid+1,r,xx); 33 } 34 int main(){ 35 int n,m,v,xx,x,y;scanf("%d%d",&n,&m); 36 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 37 build(root[0],1,n); 38 for (int i=1;i<=m;i++){ 39 scanf("%d%d",&v,&xx); 40 if (xx==1){ 41 scanf("%d%d",&x,&y); 42 update(root[i],root[v],1,n,x,y); 43 } 44 else{ 45 scanf("%d",&x); 46 root[i]=root[v]; 47 int ans=query(root[i],1,n,x); 48 printf("%d\n",ans); 49 } 50 } 51 return 0; 52 }
2,可持久化并查集
luogu3402:https://www.luogu.org/problem/P3402
题意:初始有$n$个集合,进行$m$次操作:$1 a b$合并a,b所在集合;$2 k$回到第k次操作之后的状态(查询算作操作);$3 a b$询问a,b是否属于同一集合,是则输出1否则输出0。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=2e5+10; 4 struct node{ 5 int l,r,fa,level; 6 }tree[maxn*100]; 7 int root[maxn],sz=0,n,m; 8 void build(int &x,int l,int r){ 9 x=++sz; 10 if (l==r){ 11 tree[x].fa=l; 12 return ; 13 } 14 int mid=(l+r)>>1; 15 build(tree[x].l,l,mid); 16 build(tree[x].r,mid+1,r); 17 } 18 void update(int &x,int y,int l,int r,int xx,int fa){ 19 x=++sz; tree[x]=tree[y]; 20 if (l==r){ 21 tree[x].fa=fa; 22 return ; 23 } 24 int mid=(l+r)>>1; 25 if (xx<=mid) update(tree[x].l,tree[x].l,l,mid,xx,fa); 26 else update(tree[x].r,tree[y].r,mid+1,r,xx,fa); 27 } 28 void add_level(int x,int l,int r,int xx){ 29 if (l==r){ 30 tree[x].level++; 31 return ; 32 } 33 int mid=(l+r)>>1; 34 if (xx<=mid) add_level(tree[x].l,l,mid,xx); 35 else add_level(tree[x].r,mid+1,r,xx); 36 } 37 int query(int x,int l,int r,int xx){ 38 if (l==r) return x; 39 int mid=(l+r)>>1; 40 if (xx<=mid) query(tree[x].l,l,mid,xx); 41 else query(tree[x].r,mid+1,r,xx); 42 } 43 int find(int root,int x){ //询问x在root版本下的祖先 44 int fa=query(root,1,n,x); 45 if (tree[fa].fa==x) return fa; 46 else return find(root,tree[fa].fa); 47 } 48 int main(){ 49 int xx,x,y;scanf("%d%d",&n,&m); 50 build(root[0],1,n); 51 for (int i=1;i<=m;i++){ 52 scanf("%d",&xx); 53 if (xx==1){ 54 scanf("%d%d",&x,&y); 55 root[i]=root[i-1]; 56 int fx=find(root[i],x),fy=find(root[i],y); 57 if (fx!=fy){ 58 if (tree[fx].level<tree[fy].level) swap(fx,fy); 59 update(root[i],root[i-1],1,n,tree[fy].fa,tree[fx].fa);//按秩合并 60 if (tree[fx].level==tree[fy].level) add_level(root[i],1,n,tree[fx].fa); 61 } 62 } 63 else if (xx==2){ 64 scanf("%d",&x); 65 root[i]=root[x]; 66 } 67 else{ 68 scanf("%d%d",&x,&y); 69 root[i]=root[i-1]; 70 int fx=find(root[i],x),fy=find(root[i],y); 71 if (fx==fy) printf("1\n"); else printf("0\n"); 72 } 73 } 74 return 0; 75 }