洛谷P3402 可持久化并查集
n个集合 m个操作
操作:
-
1 a b
合并a,b所在集合 -
2 k
回到第k次操作之后的状态(查询算作操作) -
3 a b
询问a,b是否属于同一集合,是则输出1否则输出0
说是可持久化并查集,实际上是把并查集的所有find和merge操作都放到可持久化数组上做,这样可以做到完全可持久化(不仅能查询某个历史版本,而且还能在某个历史版本的基础上进行修改)
注意并查集要按秩合并
可持久化数组可以用可持久化线段树(主席树)或者可持久化平衡树实现,理论上平衡树应该更快一些而且更省内存(但也省不了多少)
线段树版:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=2e5+10; 4 int rt[N],fa[N*20],mxd[N*20],ls[N*20],rs[N*20],tot,n,m; 5 #define mid ((l+r)>>1) 6 int cpy(int v) {int u=++tot; fa[u]=fa[v],mxd[u]=mxd[v],ls[u]=ls[v],rs[u]=rs[v]; return u;} 7 int qry(int* a,int p,int& u,int l=1,int r=n) { 8 if(l==r)return a[u]; 9 return p<=mid?qry(a,p,ls[u],l,mid):qry(a,p,rs[u],mid+1,r); 10 } 11 void upd(int* a,int p,int x,int v,int& u,int l=1,int r=n) { 12 u=cpy(v); 13 if(l==r) {a[u]=x; return;} 14 p<=mid?upd(a,p,x,ls[v],ls[u],l,mid):upd(a,p,x,rs[v],rs[u],mid+1,r); 15 } 16 int fd(int x,int u) { 17 int fx=qry(fa,x,u); 18 return fx?fd(fx,u):x; 19 } 20 void mg(int x,int y,int& u) { 21 int fx=fd(x,u),fy=fd(y,u); 22 if(fx==fy)return; 23 int dx=qry(mxd,fx,u),dy=qry(mxd,fy,u); 24 if(dx>dy)swap(fx,fy),swap(dx,dy); 25 upd(fa,fx,fy,u,u); 26 if(dx==dy)upd(mxd,fy,dx+1,u,u); 27 } 28 int main() { 29 mxd[0]=1; 30 scanf("%d%d",&n,&m); 31 for(int i=1; i<=m; ++i) { 32 rt[i]=rt[i-1]; 33 int f,x,y; 34 scanf("%d",&f); 35 if(f==1)scanf("%d%d",&x,&y),mg(x,y,rt[i]); 36 else if(f==2)scanf("%d",&x),rt[i]=rt[x]; 37 else scanf("%d%d",&x,&y),printf("%d\n",fd(x,rt[i])==fd(y,rt[i])); 38 } 39 return 0; 40 }
平衡树版:(由于没有旋转分裂等操作所以代码和线段树基本没区别,只是二分判断的条件稍微改了一下)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=2e5+10; 4 int rt[N],fa[N*20],mxd[N*20],ls[N*20],rs[N*20],tot,n,m; 5 #define mid ((l+r)>>1) 6 int cpy(int v) {int u=++tot; fa[u]=fa[v],mxd[u]=mxd[v],ls[u]=ls[v],rs[u]=rs[v]; return u;} 7 int qry(int* a,int p,int& u,int l=1,int r=n) { 8 if(p==mid)return a[u]; 9 return p<mid?qry(a,p,ls[u],l,mid-1):qry(a,p,rs[u],mid+1,r); 10 } 11 void upd(int* a,int p,int x,int v,int& u,int l=1,int r=n) { 12 u=cpy(v); 13 if(p==mid) {a[u]=x; return;} 14 p<mid?upd(a,p,x,ls[v],ls[u],l,mid-1):upd(a,p,x,rs[v],rs[u],mid+1,r); 15 } 16 int fd(int x,int u) { 17 int fx=qry(fa,x,u); 18 return fx?fd(fx,u):x; 19 } 20 void mg(int x,int y,int& u) { 21 int fx=fd(x,u),fy=fd(y,u); 22 if(fx==fy)return; 23 int dx=qry(mxd,fx,u),dy=qry(mxd,fy,u); 24 if(dx>dy)swap(fx,fy),swap(dx,dy); 25 upd(fa,fx,fy,u,u); 26 if(dx==dy)upd(mxd,fy,dx+1,u,u); 27 } 28 int main() { 29 mxd[0]=1; 30 scanf("%d%d",&n,&m); 31 for(int i=1; i<=m; ++i) { 32 rt[i]=rt[i-1]; 33 int f,x,y; 34 scanf("%d",&f); 35 if(f==1)scanf("%d%d",&x,&y),mg(x,y,rt[i]); 36 else if(f==2)scanf("%d",&x),rt[i]=rt[x]; 37 else scanf("%d%d",&x,&y),printf("%d\n",fd(x,rt[i])==fd(y,rt[i])); 38 } 39 return 0; 40 }