1. 程式人生 > >BZOJ4998 星球聯盟(動態樹+雙連通分量+並查集)

BZOJ4998 星球聯盟(動態樹+雙連通分量+並查集)

集中 ons turn 動態樹 oot splay move 雙連通 聯盟

  即要求動態維護邊雙。出現環時將路徑上的點合並即可。LCT維護。具體地,加邊成環時makeroot+access+splay一套把這段路徑提出來,暴力dfs修改並查集祖先,並將這部分與根斷開,視為刪除這些點,以後就以並查集中的祖先代替這些點。access時更新每個點的父親。註意由於之前的刪點操作,判斷是否連通需要另開一個並查集而不能findroot。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include
<algorithm> using namespace std; #define ll long long #define N 200010 #define lson tree[k].ch[0] #define rson tree[k].ch[1] #define lself tree[tree[k].fa].ch[0] #define rself tree[tree[k].fa].ch[1] char getc(){char c=getchar();while ((c<A||c>Z)&&(c<a||c>z)&&(c<
0||c>9)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int
n,m,q,fa[N],fa2[N],size[N]; struct data{int ch[2],fa,rev; }tree[N]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} int find2(int x){return fa2[x]==x?x:fa2[x]=find2(fa2[x]);} void rev(int k){if (k) swap(lson,rson),tree[k].rev^=1;} void down(int k){if (tree[k].rev) rev(lson),rev(rson),tree[k].rev=0;} int whichson(int k){return rself==k;} bool isroot(int k){return lself!=k&&rself!=k;} void push(int k){if (!isroot(k)) push(tree[k].fa);down(k);} void move(int k) { int fa=tree[k].fa,gf=tree[fa].fa,p=whichson(k); if (!isroot(fa)) tree[gf].ch[whichson(fa)]=k;tree[k].fa=gf; tree[fa].ch[p]=tree[k].ch[!p],tree[tree[k].ch[!p]].fa=fa; tree[k].ch[!p]=fa,tree[fa].fa=k; } void splay(int k) { push(k); while (!isroot(k)) { int fa=tree[k].fa; if (!isroot(fa)) if (whichson(fa)^whichson(k)) move(k); else move(fa); move(k); } } void access(int k){for (int t=0;k;t=k,k=tree[k].fa=find(tree[k].fa)) splay(k),tree[k].ch[1]=t;} void makeroot(int k){access(k),splay(k),rev(k);} void link(int x,int y){makeroot(x),tree[x].fa=y,fa2[find2(x)]=find2(y);} void dfs(int k,int x) { if (!k) return; if (find(k)!=x) size[x]+=size[find(k)],fa[find(k)]=x; dfs(lson,x),dfs(rson,x); } void addedge(int x,int y) { if (find2(x)!=find2(y)) link(x,y); else { makeroot(x),access(y),splay(y); dfs(tree[y].ch[0],y);tree[y].ch[0]=0; } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4998.in","r",stdin); freopen("bzoj4998.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(),q=read(); for (int i=1;i<=n;i++) fa[i]=i,fa2[i]=i,size[i]=1; for (int i=1;i<=m;i++) { int x=find(read()),y=find(read()); if (x!=y) addedge(x,y); } for (int i=1;i<=q;i++) { int x=find(read()),y=find(read()); if (x!=y) addedge(x,y); if (find(x)==find(y)) printf("%d\n",size[fa[x]]); else printf("No\n"); } return 0; }

BZOJ4998 星球聯盟(動態樹+雙連通分量+並查集)