删点维护连通块个数比较难处理,所以我们就逆序来做,先处理最后状态下有多少连通块,再依次加入被删的点,这样就变删点为加点,利用并查集即可维护连通块个数。
1 /************************************************************** 2 Problem: 1015 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:1208 ms 7 Memory:11488 kb 8 ****************************************************************/ 9 10 //BZOJ 1015 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=4e5+10,M=4e5+10,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 int n,m; 32 int to[M],next[M],head[N],cnt; 33 void ins(int x,int y){to[++cnt]=y;next[cnt]=head[x];head[x]=cnt;} 34 void add(int x,int y){ins(x,y);ins(y,x);} 35 int fa[N],ans[N],des[N]; 36 int Find(int x){return x==fa[x] ? x : fa[x]=Find(fa[x]);} 37 bool sign[N],vis[N]; 38 void dfs(int x){ 39 vis[x]=1; 40 for(int i=head[x];i;i=next[i]) 41 if (!vis[to[i]] && !sign[to[i]]){ 42 fa[to[i]]=fa[x]; 43 dfs(to[i]); 44 } 45 } 46 47 int main(){ 48 #ifndef ONLINE_JUDGE 49 freopen("1015.in","r",stdin); 50 freopen("1015.out","w",stdout); 51 #endif 52 n=getint(); m=getint(); 53 int x,y; 54 F(i,1,m){ 55 x=getint(); y=getint(); 56 add(x,y); 57 } 58 int q=getint(); 59 F(i,1,q){ 60 des[i]=getint(); sign[des[i]]=1; 61 } 62 rep(i,n) fa[i]=i; 63 int cnt=0; 64 rep(i,n) if (!sign[i] && !vis[i]){ 65 dfs(i); 66 cnt++; 67 } 68 ans[q]=cnt; 69 D(i,q,1){ 70 x=des[i];cnt++;sign[x]=0; 71 for(int j=head[x];j;j=next[j]) 72 if (!sign[to[j]]){ 73 int f1=Find(to[j]),f2=Find(x); 74 if (f1!=f2) {fa[f1]=f2;cnt--;} 75 } 76 ans[i-1]=cnt; 77 } 78 F(i,0,q) printf("%d\n",ans[i]); 79 return 0; 80 }