洛谷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 }

 

 

posted @ 2019-10-05 20:18  jrltx  阅读(167)  评论(0编辑  收藏  举报