可持久化并查集的模板题……
做法好像很多,可以标号法,可以森林法。
本来有O(mloglogn)的神算法(按秩合并+倍增),然而我这种鶸渣就只会写O(mlog2n)的民科算法……再加上人傻常数大如狗,速度简直虚死……
言归正传,鉴于标号法用的不多,这里用的是森林法。又由于并查集的路径压缩只能均摊logn,如果可持久化一下就废了。所以路径压缩大可不写,正好偷偷懒。
当然,路径压缩都省了,那按秩合并就不能不写了(要不然为啥要出加强版……)。然而我太鶸,不会写按秩合并,一向都是用按大小合并代替的……不过效果还不错,复杂度好像也是个log。
可持久化数组好像有用vector记录修改的神写法,然而我这种鶸渣只会写可持久化线段树……本来就是nlogn了,再乘上一个logn,运行时间实在感人……
总之,写的是可持久化线段树+按秩合并+暴力找父亲(不过貌似大家都是写的按秩合并暴力?然而明明同样O(mlog2n)的算法我就是最慢的那个……)。代码丑,不愿看……就算了……
1 /************************************************************** 2 Problem: 3674 3 User: hzoier 4 Language: C++ 5 Result: Accepted 6 Time:1636 ms 7 Memory:201612 kb 8 ****************************************************************/ 9 #include<cstdio> 10 #include<cstring> 11 #include<algorithm> 12 using namespace std; 13 const int maxn=200010; 14 int findroot(int); 15 void mergeset(int,int); 16 void build(int,int,int&); 17 void modify(int,int,int&); 18 void query(int,int,int); 19 int copy(int); 20 int lc[maxn<<6],rc[maxn<<6],a[maxn<<6],b[maxn<<6],root[maxn],cnt=0; 21 int n,m,d,x,y,k,prt,size,now,ans=0; 22 int main(){ 23 scanf("%d%d",&n,&m); 24 build(1,n,root[0]); 25 for(now=1;now<=m;now++){ 26 scanf("%d",&d); 27 if(d==1){ 28 scanf("%d%d",&x,&y); 29 x^=ans;y^=ans; 30 root[now]=copy(root[now-1]); 31 mergeset(x,y); 32 } 33 else if(d==3){ 34 scanf("%d%d",&x,&y); 35 x^=ans;y^=ans; 36 root[now]=copy(root[now-1]); 37 printf("%d ",ans=(int)(findroot(x)==findroot(y))); 38 } 39 else{ 40 scanf("%d",&x); 41 x^=ans; 42 root[now]=copy(root[x]); 43 } 44 } 45 return 0; 46 } 47 int findroot(int x){ 48 for(;;){ 49 k=x; 50 query(1,n,root[now]); 51 if(prt==x)return x; 52 x=prt; 53 } 54 return x; 55 } 56 void mergeset(int x,int y){ 57 x=findroot(x);y=findroot(y); 58 if(x==y)return; 59 k=x; 60 query(1,n,root[now]); 61 int sx=size; 62 k=y; 63 query(1,n,root[now]); 64 if(sx>size)swap(x,y); 65 sx+=size; 66 size=0; 67 k=x; 68 prt=y; 69 modify(1,n,root[now]); 70 k=y; 71 size=sx; 72 modify(1,n,root[now]); 73 } 74 void build(int l,int r,int &rt){ 75 rt=++cnt; 76 if(l==r){ 77 a[rt]=l; 78 b[rt]=1; 79 return; 80 } 81 int mid=(l+r)>>1; 82 build(l,mid,lc[rt]); 83 build(mid+1,r,rc[rt]); 84 } 85 void modify(int l,int r,int &rt){ 86 rt=copy(rt); 87 if(l==r){ 88 if(prt)a[rt]=prt; 89 if(size)b[rt]=size; 90 return; 91 } 92 int mid=(l+r)>>1; 93 if(k<=mid)modify(l,mid,lc[rt]); 94 else modify(mid+1,r,rc[rt]); 95 } 96 void query(int l,int r,int rt){ 97 if(l==r){ 98 prt=a[rt]; 99 size=b[rt]; 100 return; 101 } 102 int mid=(l+r)>>1; 103 if(k<=mid)query(l,mid,lc[rt]); 104 else query(mid+1,r,rc[rt]); 105 } 106 int copy(int rt){ 107 int x=++cnt; 108 lc[x]=lc[rt]; 109 rc[x]=rc[rt]; 110 a[x]=a[rt]; 111 b[x]=b[rt]; 112 return x; 113 }
尽头和开端,总有一个在等你。