BZOJ 2959: 长跑 lct 双联通分量 并查集 splay
http://www.lydsy.com/JudgeOnline/problem.php?id=2959
用两个并查集维护双联通分量的编号和合并。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 const int maxn=800010; 9 int n,m; 10 int fa[maxn]={},ch[maxn][2]={},siz[maxn]={},val[maxn]={},rev[maxn]; 11 int shu[maxn]={}; 12 int sta[maxn]={},tail=0; 13 int p[maxn]={},b[maxn]={}; 14 inline int read(){ 15 int x=0;int f=1;char ch=getchar(); 16 while(ch<'0'||ch>'9'){ 17 if(ch=='-')f=-1; 18 ch=getchar(); 19 } 20 while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 21 return x*f; 22 } 23 int findfa(int x){ 24 if(p[x]==x)return x; 25 return p[x]=findfa(p[x]); 26 } 27 int bel(int x){ 28 if(b[x]==x)return x; 29 return b[x]=bel(b[x]); 30 } 31 inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} 32 inline void updata(int x){ siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+val[x];} 33 inline void rotate(int x){ 34 int y=fa[x];int fy=fa[y]; 35 int l=ch[y][0]==x?0:1;int r=l^1; 36 if(!isroot(y)){ 37 if(ch[fy][0]==y)ch[fy][0]=x; 38 else ch[fy][1]=x; 39 } 40 fa[ch[x][r]]=y;fa[y]=x;fa[x]=fy; 41 ch[y][l]=ch[x][r]; ch[x][r]=y; 42 updata(y); 43 } 44 inline void pushdown(int x){ 45 if(rev[x]){ 46 swap(ch[x][0],ch[x][1]); 47 if(ch[x][0])rev[ch[x][0]]^=1; 48 if(ch[x][1])rev[ch[x][1]]^=1; 49 rev[x]=0; 50 } 51 } 52 inline void splay(int x){ 53 x=bel(x);fa[x]=bel(fa[x]); 54 int y,fy,w=x; 55 sta[++tail]=w; 56 while(!isroot(w)){ 57 fa[w]=bel(fa[w]);sta[++tail]=fa[w]; 58 fa[fa[w]]=bel(fa[fa[w]]); 59 w=fa[w]; 60 } 61 while(tail)pushdown(sta[tail--]); 62 63 while(!isroot(x)){ 64 y=fa[x];fy=fa[y]; 65 if(!isroot(y)){ 66 if((ch[y][0]==x)^(ch[fy][0]==y))rotate(x); 67 else rotate(y); 68 }rotate(x); 69 }updata(x); 70 } 71 inline void Access(int x){ 72 int y=0; 73 while(x){ 74 x=bel(x); 75 splay(x);ch[x][1]=y; 76 updata(x); 77 y=x;x=fa[x]; 78 } 79 } 80 inline void Reverse(int x){ 81 Access(x);splay(x); 82 rev[x]^=1; 83 } 84 inline void Link(int x,int y){ 85 Reverse(x);fa[x]=y; 86 } 87 queue< int >q; 88 inline void Merge(int x,int y){ 89 Reverse(y);Access(x);splay(x); 90 int cnt=siz[x]; 91 q.push(x); 92 while(!q.empty()){ 93 x=q.front();q.pop(); 94 if(ch[x][0])q.push(ch[x][0]); 95 if(ch[x][1])q.push(ch[x][1]); 96 b[bel(x)]=b[bel(y)]; 97 val[x]=siz[x]=fa[x]=ch[x][0]=ch[x][1]=0; 98 } 99 val[y]=siz[y]=cnt;fa[y]=0; 100 } 101 int main(){ 102 //freopen("now.in","r",stdin); 103 n=read();m=read();; 104 for(int i=1;i<=n;i++){val[i]=read();shu[i]=val[i];siz[i]=val[i];} 105 for(int i=1;i<=n;i++)p[i]=i,b[i]=i; 106 int op,x,y,xx,yy; 107 for(int i=1;i<=m;i++){ 108 op=read();x=read();y=read(); 109 if(op==1){ 110 x=bel(x);y=bel(y); 111 if(x!=y){ 112 xx=findfa(x);yy=findfa(y); 113 if(xx==yy) Merge(x,y); 114 else {Link(x,y);p[xx]=yy;} 115 } 116 } 117 else if(op==2){ 118 xx=bel(x); 119 if(shu[x]!=y){ 120 Access(xx);splay(xx); 121 siz[xx]+=y-shu[x]; 122 val[xx]+=y-shu[x]; 123 shu[x]=y; 124 } 125 } 126 else{ 127 x=bel(x);y=bel(y); 128 if(findfa(x)!=findfa(y)){ 129 printf("-1\n"); 130 } 131 else{ 132 Reverse(x);Access(y);splay(y); 133 printf("%d\n",siz[y]); 134 } 135 } 136 } 137 return 0; 138 }
注意一下双联通分量编号的维护