【JZOJ3875】星球联盟(alliance)

来源:互联网 发布:lol韩服登不上网络错误 编辑:程序博客网 时间:2024/06/09 16:40

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 400010using namespace std;int to[M],nx[M],ls[N],num=0;struct node{    int x,y;    bool tr;}b[N*2];int tot=0;int f[N],d[N],sz[N],fa[N];bool bz[N];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[N];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)]);    }}
1 0
原创粉丝点击