滚下去补学考之前更一发
基于可持久化线段树实现(我不很喜欢“主席树”这个名字),注意不能路径压缩,首先这与可持久化的思想冲突(即尽量利用之前已有的部分,只修改有修改的部分,路径压缩压完了岂不是gg),其次每次压缩还会有一个log的时间复杂度(查询),然后复杂度就是$O(nlog n)$的
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100005; 6 struct a 7 { 8 int bel,pst,siz; 9 }aset[N*44]; 10 int root[N],son[N*44][2]; 11 int n,m,t1,t2,t3,tot,ans; 12 int Create(int l,int r) 13 { 14 int nde=++tot; 15 if(l==r) 16 aset[nde]=(a){l,l,1}; 17 else 18 { 19 int mid=(l+r)/2; 20 son[nde][0]=Create(l,mid); 21 son[nde][1]=Create(mid+1,r); 22 } 23 return nde; 24 } 25 int Insert(int pre,int l,int r,int pos,a task) 26 { 27 int nde=++tot; 28 son[nde][0]=son[pre][0]; 29 son[nde][1]=son[pre][1]; 30 if(l<r) 31 { 32 int mid=(l+r)/2; 33 if(pos<=mid) 34 son[nde][0]=Insert(son[pre][0],l,mid,pos,task); 35 else 36 son[nde][1]=Insert(son[pre][1],mid+1,r,pos,task); 37 } 38 else aset[nde]=task; 39 return nde; 40 } 41 a Query(int nde,int l,int r,int pos) 42 { 43 if(l==r) 44 return aset[nde]; 45 else 46 { 47 int mid=(l+r)/2; 48 if(pos<=mid) return Query(son[nde][0],l,mid,pos); 49 else return Query(son[nde][1],mid+1,r,pos); 50 } 51 } 52 int finda(int b,int x) 53 { 54 int f=Query(b,1,n,x).bel; 55 return (f==x)?x:finda(b,f); 56 } 57 int main() 58 { 59 scanf("%d%d",&n,&m); 60 root[0]=Create(1,n); 61 for(int i=1;i<=m;i++) 62 { 63 scanf("%d%d",&t1,&t2); 64 if(t1==1) 65 { 66 scanf("%d",&t3); root[i]=root[i-1]; 67 int f1=finda(root[i],t2),f2=finda(root[i],t3); 68 a r1=Query(root[i],1,n,f1),r2=Query(root[i],1,n,f2); 69 if(r1.bel!=r2.bel) 70 { 71 if(r1.siz<r2.siz) swap(r1,r2); 72 r1.siz+=r2.siz,r2.bel=r1.bel; 73 root[i]=Insert(root[i],1,n,r2.pst,r2); 74 root[i]=Insert(root[i],1,n,r1.pst,r1); 75 } 76 } 77 else if(t1==2) 78 root[i]=root[t2]; 79 else 80 { 81 scanf("%d",&t3),root[i]=root[i-1]; 82 printf("%d ",finda(root[i],t2)==finda(root[i],t3)); 83 } 84 } 85 return 0; 86 }