bzoj3674 可持久化并查集

我是萌萌的任意门

可持久化并查集的模板题……

做法好像很多,可以标号法,可以森林法。

本来有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\n",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 }
View Code

 

尽头和开端,总有一个在等你。

posted @ 2016-11-07 20:49  AntiLeaf  阅读(165)  评论(4编辑  收藏  举报