您的位置:首页 > 其它

【jzoj3875】【星球联盟】【树】【并查集】

2017-01-18 21:10 323 查看

题目大意

在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。但是,组成联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有公共隧道的路径。为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。

解题思路

离线所有询问,将最早出现的边构成树,其他的先存起来,用询问边构成树边的打no的标记。将给出的边构成的环用并查集并起来,暴力并即可,深度大的先并,因为只会并一次,维护集合和点数即可。

code

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define min(a,b) ((a<b)?a:b)
#define max(a,b) ((a>b)?a:b)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=2*1e5,inf=1e9;
int n,m,p,fa[maxn+10][10],num[maxn+10][10],gra,to[maxn*2+10],next[maxn*2+10],
begin[maxn+10],f[maxn+10],tag[maxn+10],u[maxn+10],v[maxn+10],uu[maxn+10],vis[maxn+10],
vv[maxn+10],dep[maxn+10];
int get(int x,int p){
if(!fa[x][p])return x;
return fa[x][p]=get(fa[x][p],p);
}
int connect(int x,int y,int p){
int fau=get(x,p),fav=get(y,p);
if(fau==fav)return 0;
fa[fau][p]=fav;
num[fav][p]+=num[fau][p];
return 1;
}
void insert(int x,int y){
to[++gra]=y;
next[gra]=begin[x];
begin[x]=gra;
}
void dfs(int now,int pre){
vis[now]=1;
for(int i=begin[now];i;i=next[i])if(to[i]!=pre){
f[to[i]]=now;dep[to[i]]=dep[now]+1;
dfs(to[i],now);
}
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d%d%d",&n,&m,&p);
fo(i,1,n)num[i][0]=num[i][1]=1;int cnt=0,tmppp=0;
fo(i,1,m){
scanf("%d%d",&u[i],&v[i]);
if(connect(u[i],v[i],0)){insert(u[i],v[i]),insert(v[i],u[i]);tmppp++;}
else uu[++cnt]=u[i],vv[cnt]=v[i];
}
fo(i,1,p){
scanf("%d%d",&u[i],&v[i]);
if(connect(u[i],v[i],0)){
tag[i]=1;tmppp++;
insert(u[i],v[i]);insert(v[i],u[i]);
}
}
fo(i,1,n)if(!vis[i]){
dep[i]=1;dfs(i,0);
}

fo(i,1,cnt){
int fau=uu[i],fav=vv[i],tmp,tmpp=0;
while((fau=get(fau,1))!=(fav=get(fav,1))){
if(dep[fau]<dep[fav])swap(fau,fav);
connect(fau,f[fau],1);
//if((fau==get(fau,1))&&(fav==get(fav,1)))tmpp++;
//if(tmpp>10)break;
}
}
fo(i,1,p)if(tag[i])printf("No\n");else{
int fau=u[i],fav=v[i],tmp,tmpp=0;;
while((fau=get(fau,1))!=(fav=get(fav,1))){
if(dep[fau]<dep[fav])swap(fau,fav);
connect(fau,f[fau],1);
//if((fau==get(fau,1))&&(fav==get(fav,1)))tmpp++;
//if(tmpp>10)break;
}
printf("%d\n",num[get(fau,1)][1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: