BZOJ1015 JSOI2008 星球大战starwars 并查集

题意:给定一张无向图,不断从图上删点,询问每次删点后联通块的数量
题解:离线,在删完点后的图上不断加点,用并查集维护联通性。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=400000+2;
struct Hash{
    int u;
    Hash *next;
}*Tab[MAXN],Mem[MAXN];
int N,M,C,K,P[MAXN],Ans[MAXN],f[MAXN];
bool Flag[MAXN];

void Insert(int u,int v){
    Mem[C].u=v,Mem[C].next=Tab[u];
    Tab[u]=&Mem[C];
    C++;
}

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

int main(){
    scanf("%d %d",&N,&M);
    for(int i=1,u,v;i<=M;i++){
        scanf("%d %d",&u,&v);
        Insert(u,v),Insert(v,u);
    }
    scanf("%d",&K);
    for(int i=1;i<=K;i++) scanf("%d",P+i),Flag[P[i]]=1;

    for(int i=0;i<N;i++) f[i]=i;
    for(int i=0;i<N;i++)
        if(!Flag[i]){
            Ans[K+1]++;
            for(Hash *p=Tab[i];p;p=p->next)
                if(!Flag[p->u]){
                    int a=Find(i),b=Find(p->u);
                    if(a!=b) f[a]=b,Ans[K+1]--;
                }
        }

    Ans[K]=Ans[K+1];
    for(int i=K;i;i--,Ans[i]=Ans[i+1]){
        Flag[P[i]]=0,Ans[i]++;
        for(Hash *p=Tab[P[i]];p;p=p->next)
            if(!Flag[p->u]){
                int a=Find(P[i]),b=Find(p->u);
                if(a!=b) f[a]=b,Ans[i]--;
            }
    }
    for(int i=1;i<=K+1;i++) printf("%d\n",Ans[i]);

    return 0;
}
View Code

 

posted @ 2017-02-26 01:48  WDZRMPCBIT  阅读(184)  评论(0编辑  收藏  举报