bzoj4998 星球联盟

bzoj4998 星球联盟


原题链接


题解

先按照输入顺序建一棵树(森林),然后用一个并查集维护联盟的关系,对于不是树上的边\(a-b\),就把\(a-lca(a,b),b-lca(a,b)\)全部合并(一个圈),输出\(a\)所在并查集的\(Siz\),树边输出\(No\)


Code


// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cmath>
#define Fname "CJOJ2550"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il int gi(){
    rg int x=0;rg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}
const int maxn=200100,maxm=200100<<2;
int id,fir[maxn],nxt[maxm],dis[maxm];
int fa[maxn],Fa[maxn],FA[maxn],dep[maxn],Siz[maxn];
int A[maxn<<1],B[maxn<<1];
bool yes[maxn<<1];
il int hd(int s){return fa[s]==s?s:(fa[s]=hd(fa[s]));}
il int Hd(int s){return Fa[s]==s?s:(Fa[s]=Hd(Fa[s]));}
il vd add(int a,int b){nxt[++id]=fir[a],fir[a]=id,dis[id]=b;}
il vd dfs(int now){erep(i,now)if(!dep[dis[i]])dep[dis[i]]=dep[now]+1,FA[dis[i]]=now,dfs(dis[i]);}
il vd doit(int s){
    rg int a=Hd(s),b=Hd(FA[s]);
    if(a^b)Siz[b]+=Siz[a],Fa[a]=b;
}
int main(){
    // freopen(Fname".in","r",stdin);
    // freopen(Fname".out","w",stdout);
    int a,b,n=gi(),m=gi(),p=gi();
    rep(i,1,n)fa[i]=Fa[i]=i,Siz[i]=1;
    rep(i,1,m+p){
	a=A[i]=gi(),b=B[i]=gi();
	if(hd(a)^hd(b))add(a,b),add(b,a),fa[hd(a)]=hd(b);
	else yes[i]=1;
    }
    rep(i,1,n)if(!FA[i])FA[i]=-1,dep[i]=1,dfs(i);
    rep(i,1,m)if(yes[i]){
	a=A[i],b=B[i];
	while(a^b)
	    if(dep[a]>dep[b])doit(a),a=FA[a];
	    else doit(b),b=FA[b];
    }
    rep(i,1,p)if(yes[i+m]){
	a=A[i+m],b=B[i+m];
	while(a^b)
	    if(dep[a]>dep[b])doit(a),a=FA[a];
	    else doit(b),b=FA[b];
	printf("%d\n",Siz[Hd(a)]);
    }else puts("No");
    return 0;
}
posted @ 2017-09-04 11:10  菜狗xzz  阅读(159)  评论(0编辑  收藏  举报