csu 1601 1601: War (并查集 kruskal)

题意:有n个村子 由m条路联通 其中q条路会依次被摧毁

         问每次摧毁后会有多少片村庄被孤立

思路:首先算出q条路都被摧毁后被孤立的村庄数

        然后再逆序把每条路修复上 每修复一条孤立的村庄就减少一片

        最后再输出每次记录的结果

 

#include<cstdio>

#include<cstring>

#include<iostream>

#include<algorithm>

using namespace std;

int vis[100000+100];

int  fa[100000+100];

int del[100000+100];

int ans[100000+100];

int n,m,q;

struct Edge

{

    int f,to;

};

Edge edge[100000+100];

int fin(int a)

{

    return fa[a]==a?a:fa[a]=fin(fa[a]);

}

int kru(int x,int y)

{

    int fx=fin(x);

    int fy=fin(y);

    if(fx!=fy)

    {

       fa[fx]=fy;

       return 1;

    }

    return 0;

}

int main()

{



    int i,j,k;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        for(i=0;i<=n;i++) fa[i]=i;

        memset(vis,0,sizeof(vis));



        for(i=1;i<=m;i++)

        {

            scanf("%d%d",&edge[i].f,&edge[i].to);

        }

        scanf("%d",&q);

        for(i=0;i<q;i++)

        {

            scanf("%d",&del[i]);

            vis[del[i]]=1;

        }

        int cnt=0;

        int tmp=n;

        for(i=1;i<=m;i++)

        {

            if(vis[i]==0)

            {

                if(kru(edge[i].f,edge[i].to)==1) tmp--;

            }

        }

        ans[cnt++]=tmp;

        for(i=q-1;i>0;i--)

        {

            j=del[i];

            if(kru(edge[j].f,edge[j].to)==1) tmp--;

            ans[cnt++]=tmp;

        }

        for(i=cnt-1;i>=0;i--)

        {

            printf("%d",ans[i]);

            if(i!=0) printf(" ");

            else printf("\n");

        }

    }

    return 0;

}

  

你可能感兴趣的:(并查集)