您的位置:首页 > 其它

【JZOJ3875】星球联盟(alliance)

2017-01-19 21:28 369 查看

Description

在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。

但是,组成联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有公共隧道的路径。

为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。

Solution

两个星球同属于一个联盟,等于它们之间本来有树边相连,然后再给它们直接或间接连上一条边。

于是这题我们将初始边和询问边的树边加进去构成树或森林,对于询问的边是树边的就输出No。这个可以用Tarjan缩环或者用并查集实现。

对于这棵树(或森林),我们求出深度,然后对于每个非树边,加入它相当于边的两个端点之间路径的所有点都能属于一个联盟。于是并查集缩点即可。

那么对于一条边的查询,就是查询两个端点所在并查集的大小。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define rep(i,x) for(int i=ls[x];i;i=nx[i])
#define N 200010
#define M 400010
using namespace std;
int to[M],nx[M],ls
,num=0;
struct node{
int x,y;
bool tr;
}b[N*2];
int tot=0;
int f
,d
,sz
,fa
;
bool bz
;
void link(int x,int y)
{
num++;
to[num]=y;
nx[num]=ls[x];
ls[x]=num;
}
int find(int x){
return f[x]==x?x:f[x]=find(f[x]);
}
int dl
;
void bfs(int s)
{
bz[s]=true;
int l=0,r=1;
dl[1]=s;
while(l<r)
{
l++;
int x=dl[l];
rep(i,x)
{
int v=to[i];
if(bz[v]) continue;
bz[v]=true;
d[v]=d[x]+1;
fa[v]=x;
dl[++r]=v;
}
}
}
int lca(int u,int v)
{
u=find(u),v=find(v);
if(u==v) return u;
if(d[u]<d[v]) swap(u,v);
int t=lca(fa[u],v);
f[u]=t;
sz[t]+=sz[u];
}
int main()
{
freopen("alliance.in","r",stdin);
freopen("alliance.out","w",stdout);
int n,m,p;
scanf("%d %d %d",&n,&m,&p);
fo(i,1,n) sz[i]=1,f[i]=i;
fo(i,1,m+p)
{
int x,y;
scanf("%d %d",&x,&y);
b[i].x=x,b[i].y=y;
int fx=find(x),fy=find(y);
if(fx!=fy)
{
f[fy]=fx;
b[i].tr=true;
link(x,y);
link(y,x);
}
}
fo(i,1,n)
if(!bz[i]) d[i]=1,bfs(i);
memset(f,0,sizeof(f));
fo(i,1,n) f[i]=i;
fo(i,1,m)
if(!b[i].tr) lca(b[i].x,b[i].y);
fo(i,m+1,m+p)
{
int x=b[i].x,y=b[i].y;
if(b[i].tr) printf("No\n");
else printf("%d\n",sz[lca(x,y)]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: