bzoj3673可持久化并查集 by zky&&bzoj3674可持久化并查集加强版

bzoj3673可持久化并查集 by zky

题意:

维护可以恢复到第k次操作后的并查集。

题解:

用可持久化线段树维护并查集的fa数组和秩(在并查集里的深度),不能路径压缩所以用按秩启发式合并,可以使合并均摊复杂度为O(nlog2n)。可持久化线段树实际上就是在更新节点时按主席树的插入方式新建一条路径(其实主席树就是可持久化权值线段树)。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 30000
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 using namespace std;
 7 
 8 int fa[maxn*15],ch[maxn*15][2],dep[maxn*15],pos[maxn*15],sz,n,m,rt[maxn];
 9 inline int read(){
10     char ch=getchar(); int f=1,x=0;
11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
12     return f*x;
13 }
14 void build(int &x,int l,int r){
15     x=++sz; if(l==r){fa[x]=l; dep[x]=1; pos[x]=l; return;}
16     int mid=(l+r)>>1; build(ch[x][0],l,mid); build(ch[x][1],mid+1,r);
17 }
18 void updatefa(int &x,int l,int r,int a,int b){
19     sz++; fa[sz]=fa[x]; dep[sz]=dep[x]; pos[sz]=pos[x]; ch[sz][0]=ch[x][0]; ch[sz][1]=ch[x][1];
20     x=sz; if(l==r){fa[x]=b; return;}
21     int mid=(l+r)>>1; if(a<=mid)updatefa(ch[x][0],l,mid,a,b);else updatefa(ch[x][1],mid+1,r,a,b);
22 }
23 void updatedep(int &x,int l,int r,int a,int b){
24     sz++; fa[sz]=fa[x]; dep[sz]=dep[x]; pos[sz]=pos[x]; ch[sz][0]=ch[x][0]; ch[sz][1]=ch[x][1];
25     x=sz; if(l==r){dep[x]=b; return;}
26     int mid=(l+r)>>1; if(a<=mid)updatedep(ch[x][0],l,mid,a,b);else updatedep(ch[x][1],mid+1,r,a,b);
27 }
28 int query(int x,int l,int r,int a){
29     if(l==r)return x; int mid=(l+r)>>1;
30     if(a<=mid)return query(ch[x][0],l,mid,a);else return query(ch[x][1],mid+1,r,a);
31 }
32 int find(int x,int y){
33     int z=query(x,1,n,y); if(fa[z]==pos[z])return z;else return find(x,fa[z]);
34 }
35 void merge(int &s,int x,int y){
36     int z1=find(s,x),z2=find(s,y); if(pos[z1]==pos[z2])return; if(dep[z1]>dep[z2])swap(z1,z2);
37     int abc=max(dep[z2],dep[z1]+1); updatefa(s,1,n,pos[z1],pos[z2]); updatedep(s,1,n,pos[z2],abc);
38 }
39 int main(){
40     n=read(); m=read(); build(rt[0],1,n);
41     inc(i,1,m){
42         int opt=read();
43         if(opt==1){int a=read(),b=read(); rt[i]=rt[i-1]; merge(rt[i],a,b);}
44         if(opt==2){int k=read(); rt[i]=rt[k];}
45         if(opt==3){
46             int a=read(),b=read(); rt[i]=rt[i-1];
47             if(pos[find(rt[i],a)]==pos[find(rt[i],b)])puts("1");else puts("0");
48         }
49     }
50     return 0;
51 }

------------------------------------------------------------------------------------------------------------------------------------------

bzoj3674可持久化并查集加强版

题意:

同3673,但强制在线且点数操作数≤200000

题解:

T个不停,后来看黄学长博客把数组n*2(log2n)开成结果A了,后来突然明白我fa数组和dep数组是分开维护的,也就是说每次操作新建了两条路径,当然要*2,QAQ~

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 200010
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 using namespace std;
 7 
 8 int fa[maxn*50],ch[maxn*50][2],dep[maxn*50],pos[maxn*50],sz,n,m,rt[maxn];
 9 inline int read(){
10     char ch=getchar(); int f=1,x=0;
11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
12     return f*x;
13 }
14 void build(int &x,int l,int r){
15     x=++sz; if(l==r){fa[x]=l; dep[x]=1; pos[x]=l; return;}
16     int mid=(l+r)>>1; build(ch[x][0],l,mid); build(ch[x][1],mid+1,r);
17 }
18 void updatefa(int &x,int l,int r,int a,int b){
19     sz++; fa[sz]=fa[x]; dep[sz]=dep[x]; pos[sz]=pos[x]; ch[sz][0]=ch[x][0]; ch[sz][1]=ch[x][1];
20     x=sz; if(l==r){fa[x]=b; return;}
21     int mid=(l+r)>>1; if(a<=mid)updatefa(ch[x][0],l,mid,a,b);else updatefa(ch[x][1],mid+1,r,a,b);
22 }
23 void updatedep(int &x,int l,int r,int a,int b){
24     sz++; fa[sz]=fa[x]; dep[sz]=dep[x]; pos[sz]=pos[x]; ch[sz][0]=ch[x][0]; ch[sz][1]=ch[x][1];
25     x=sz; if(l==r){dep[x]=b; return;}
26     int mid=(l+r)>>1; if(a<=mid)updatedep(ch[x][0],l,mid,a,b);else updatedep(ch[x][1],mid+1,r,a,b);
27 }
28 int query(int x,int l,int r,int a){
29     if(l==r)return x; int mid=(l+r)>>1;
30     if(a<=mid)return query(ch[x][0],l,mid,a);else return query(ch[x][1],mid+1,r,a);
31 }
32 int find(int x,int y){
33     int z=query(x,1,n,y); if(fa[z]==pos[z])return z;else return find(x,fa[z]);
34 }
35 void merge(int &s,int x,int y){
36     int z1=find(s,x),z2=find(s,y); if(pos[z1]==pos[z2])return; if(dep[z1]>dep[z2])swap(z1,z2);
37     int abc=max(dep[z2],dep[z1]+1); updatefa(s,1,n,pos[z1],pos[z2]); updatedep(s,1,n,pos[z2],abc);
38 }
39 int main(){
40     n=read(); m=read(); build(rt[0],1,n); int last=0;
41     inc(i,1,m){
42         int opt=read();
43         if(opt==1){int a=read()^last,b=read()^last; rt[i]=rt[i-1]; merge(rt[i],a,b);}
44         if(opt==2){int k=read()^last; rt[i]=rt[k];}
45         if(opt==3){
46             int a=read()^last,b=read()^last; rt[i]=rt[i-1];
47             if(pos[find(rt[i],a)]==pos[find(rt[i],b)])puts("1"),last=1;else puts("0"),last=0;
48         }
49     }
50     return 0;
51 }

20160623

原文地址:https://www.cnblogs.com/YuanZiming/p/5701115.html