首页 > 技术文章 > BZOJ 4998 星球联盟

Jackpei 2019-12-04 19:07 原文

题意:给一张无向图,并不断加边 \((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\n",sum);
	}
}
} signed main() {Luitaryi::main(); return 0;}

推荐阅读