星球大战 并查集!!!

Sample Input

8 13 0 1 1 6 6 5 5 0 0 6 1 2 2 3 3 4 4 5 7 1 7 2 7 6 3 6 5 1 6 3 5

Sample Output

1 1 1 2 3 3

#include <bits/stdc++.h>
using namespace std;

int tot,n,m,d,f[400001],head[400001],q[400001],ans[400001],cnt=1;

bool used[400001], des[400001];
struct data{int to,next;}e[400001]; //next是

int find(int x){return x==f[x]?x:f[x]=find(f[x]);}

void ins(int u,int v) {//存图
    e[++cnt].to=u; e[cnt].next=head[v]; head[v]=cnt;
    e[++cnt].to=v; e[cnt].next=head[u]; head[u]=cnt;
}

void add(int x) {
    int i=head[x],p=find(x),q; //p是x的父节点,
    while(i) {
        if(used[e[i].to]) { // 如果该点被使用过
            q=find(e[i].to); //q就为e[i].to的父节点
            if(p!=q){f[q]=p;tot--;} //如果两个父节点不同(不是它本身) p为q的父节点 tot自减
        }
        i=e[i].next; //i为与它相邻的点
    } 
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) f[i]=i;

    for(int i=1;i<=m;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);
    }

    scanf("%d",&d); // d是进行的操作次数
    for(int i=1;i<=d;i++) {
        scanf("%d",&q[i]);
        des[q[i]]=1; // 记录被摧毁的星球
    }

    for(int i=0;i<n;i++) {
        if(!des[i]) { //如果该星球没有被摧毁
            tot++;  //记录没有被摧毁的星球个数
            add(i); //传入add函数(即merge函数进行并查集构图
            used[i]=1; //i已经进入图中
        }
    }
    ans[d+1]=tot;  //此时tot是除去被摧毁星球的连通块数目

    for(int i=d;i>0;i--) {
        tot++; // 摧毁一个星球首先默认会导致连通块++
        add(q[i]); //将被摧毁的星球补回去
        used[q[i]]=1; //q[i]被使用 
        ans[i]=tot;  // tot此时为该状态下的连通块数
    }

    for(int i=1;i<=d+1;i++)printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lightac/p/10721378.html