【JZOJ3875】星球联盟(alliance)

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[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)]);
    }
}
posted @ 2017-01-19 21:29  sadstone  阅读(72)  评论(0编辑  收藏  举报