BZOJ4998星球联盟——LCT+并查集(LCT动态维护边双连通分量)
题目描述
在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。但是,组成
联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能
够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有
公共隧道的路径。为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条
新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨
道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。
输入
第1行三个整数N,M和P,分别表示总星球数,初始时太空隧道的数目和即将建设的轨道数目。
第2至第M+1行,每行两个整数,表示初始时的每条太空隧道连接的两个星球编号。
第M+2行至第M+P+1行,每行两个整数,表示新建的太空隧道连接的两个星球编号。
这些太空隧道按照输入的顺序依次建成。
1≤N,M,P≤200000
输出
输出共P行。
如果这条新的太空隧道连接的两个星球属于同一个联盟,就输出一个整数,表示这两个星球所在联盟的星球数。
如果这条新的太空隧道连接的两个星球不属于同一个联盟,就输出"No"(不含引号)。
样例输入
5 3 4
1 2
4 3
4 5
2 3
1 3
4 5
2 4
1 2
4 3
4 5
2 3
1 3
4 5
2 4
样例输出
No
3
2
5
3
2
5
提示
如果两个星球属于同一个联盟,那么他们就属于一个点双,用LCT维护点双缩点后的树,用两个并查集分别维护每个点属于哪个点双及点之间连通性,加边时分两种情况讨论即可。具体操作参见BZOJ2959。
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #include<bitset> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define pr pair<int,int> #define ll long long using namespace std; int g[200010]; int fa[200010]; int f[200010]; int s[200010][2]; int sum[200010]; int st[200010]; int r[200010]; int size[200010]; int n,m,p; int opt; int x,y; int find(int x) { if(fa[x]==x) { return x; } return fa[x]=find(fa[x]); } int judge(int x) { if(g[x]==x) { return x; } return g[x]=judge(g[x]); } int is_root(int rt) { return rt!=s[find(f[rt])][0]&&rt!=s[find(f[rt])][1]; } int get(int rt) { return rt==s[find(f[rt])][1]; } void pushup(int rt) { sum[rt]=sum[s[rt][0]]+sum[s[rt][1]]+size[rt]; } void pushdown(int rt) { if(r[rt]) { swap(s[rt][0],s[rt][1]); r[s[rt][0]]^=1; r[s[rt][1]]^=1; r[rt]^=1; } } void rotate(int rt) { int fa=find(f[rt]); int anc=find(f[fa]); int k=get(rt); if(!is_root(fa)) { s[anc][get(fa)]=rt; } s[fa][k]=s[rt][k^1]; f[s[fa][k]]=fa; s[rt][k^1]=fa; f[fa]=rt; f[rt]=anc; pushup(fa); pushup(rt); } void splay(int rt) { int top=0; st[++top]=rt; for(int i=rt;!is_root(i);i=find(f[i])) { st[++top]=find(f[i]); } for(int i=top;i>=1;i--) { pushdown(st[i]); } for(int fa;!is_root(rt);rotate(rt)) { if(!is_root(fa=find(f[rt]))) { rotate(get(fa)==get(rt)?fa:rt); } } } void access(int rt) { for(int x=0;rt;x=rt,rt=find(f[rt])) { splay(rt); s[rt][1]=x; pushup(rt); } } void reverse(int rt) { access(rt); splay(rt); r[rt]^=1; } void link(int x,int y) { reverse(x); f[x]=y; g[g[x]]=g[y]; } void dfs(int x,int rt) { fa[x]=rt; if(s[x][0]) { dfs(s[x][0],rt); } if(s[x][1]) { dfs(s[x][1],rt); } } int main() { scanf("%d%d%d",&n,&m,&p); for(int i=1;i<=n;i++) { fa[i]=g[i]=i; size[i]=sum[i]=1; } for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); int fx=find(x); int fy=find(y); if(fx!=fy) { if(judge(fx)!=judge(fy)) { link(fx,fy); } else { reverse(fx); access(fy); splay(fy); size[fy]=sum[fy]; dfs(fy,fy); s[fy][0]=0; } } } for(int i=1;i<=p;i++) { scanf("%d%d",&x,&y); int fx=find(x); int fy=find(y); if(fx==fy) { reverse(fx); access(fy); splay(fy); printf("%d\n",sum[fx]); } else if(judge(fx)!=judge(fy)) { link(fx,fy); printf("No\n"); } else { reverse(fx); access(fy); splay(fy); size[fy]=sum[fy]; dfs(fy,fy); s[fy][0]=0; printf("%d\n",sum[fy]); } } }