题意:给一张无向图,并不断加边 ((u,v)),并询问 (u,v) 是否位于同一个双联通分量里,若位于同一双联通分量,输出这个双联通分量的 (size)
使用并查集+LCT维护。
有两套并查集:s1
是用来维护每个点归属哪一个强连通分量,每个点的祖先是这个强连通分量的代表节点,同时代表节点存储这个强连通分量的 (size);s2
是用来维护原始图的联通性的。
注意加边时 ((u,v)) ,我们都是对两个点所在联通分量的代表节点进行操作。
我们加边 ((u,v)) 时,首先若两个点所在的联通分量的代表节点本来不连通,那直接加边(指同时修改 s2
和 LCT)即可。
若原来两个点所在的联通分量的代表节点联通,那么我们 split(u,v)
,将这条链(当然链上的点可能是一个联通分量)的所有点缩成一个点,我们把所有遍历到的点的 s1
都指向 (u) ,使 (u) 作为新联通分量的代表节点。
#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=200010;
int n,m,q,fa[N],ch[N][2],sz[N],stk[N],sum,cur; bool tg[N];
struct ufs { int fa[N];
inline void reset(int n) {for(R i=1;i<=n;++i) fa[i]=i;}
inline int f(int x) {return x==fa[x]?x:fa[x]=f(fa[x]);}
}s1,s2;
#define ls(x) (ch[x][0])
#define rs(x) (ch[x][1])
#define rev(x) (swap(ls(x),rs(x)),tg[x]^=1)
inline bool isroot(int x) {return ls(s1.f(fa[x]))!=x&&rs(s1.f(fa[x]))!=x;}
inline void spread(int x) { if(!tg[x]) return ;
if(ls(x)) rev(ls(x)); if(rs(x)) rev(rs(x)); tg[x]=0;
}
inline void rot(int x) {
R y=s1.f(fa[x]); R z=s1.f(fa[y]); R d=ch[y][1]==x;
if(!isroot(y)) ch[z][ch[z][1]==y]=x;
fa[x]=z,fa[ch[y][d]=ch[x][d^1]]=y;
fa[ch[x][d^1]=y]=x;
}
inline void Splay(int x) {
R y=x,z,top=0; stk[++top]=x;
while(!isroot(y)) stk[++top]=y=s1.f(fa[y]);
while(top) spread(stk[top--]);
while(!isroot(x)) { y=s1.f(fa[x]); z=s1.f(fa[y]);
if(!isroot(y)) rot((ch[z][1]==y)==(ch[y][1]==x)?y:x);
rot(x);
}
}
inline void acc(int x) {for(R y=0;x;x=s1.f(fa[y=x])) Splay(x),rs(x)=y;}
inline void mrt(int x) {acc(x),Splay(x),rev(x);}
inline void split(int x,int y) {mrt(x),acc(y),Splay(x);}
inline void link(int x,int y) {mrt(x); fa[x]=y;}
inline void dfs(int x) {
if(x!=cur) sz[cur]+=sz[x],s1.fa[x]=cur;
if(ls(x)) dfs(ls(x)); if(rs(x)) dfs(rs(x));
}
inline void add(int x,int y) { sum=0;
R fx=s2.f(x),fy=s2.f(y);
if(fx==fy) {
split(x,y),cur=x,dfs(x),ls(x)=rs(x)=0,sum=sz[x];
} else s2.fa[fx]=fy,link(x,y);
}
inline void main() {
n=g(),m=g(),q=g();
for(R i=1;i<=n;++i) sz[i]=1;
s1.reset(n),s2.reset(n);
for(R i=1,u,v;i<=m;++i) u=s1.f(g()),v=s1.f(g()),add(u,v);
for(R i=1,u,v;i<=q;++i) {
u=s1.f(g()),v=s1.f(g()),add(u,v);
if(!sum) puts("No"); else printf("%d
",sum);
}
}
} signed main() {Luitaryi::main(); return 0;}