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; }