思路:离线倒序恢复被摧毁星球,同时维护联通块个数。但需要一定的优化。

具体:用邻接表存边。未被摧毁的星球记为现存;

        第一次处理将未被摧毁的边连接(并查集),算出连通块个数start;

        之后每次倒序恢复一个被摧毁的星球i,将星球i记录为已恢复,并连接i连向所有现存星球j的边。其中,每合并一次发现将原先两个联通块合并到一起(即father[j]=-1),则              start--;答案存入ans数组,最后倒序输出。

        最后注意小细节。

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int MAX=400010;
 5 struct fx{
 6     int u,v,next;
 7 }edge[MAX];
 8 int size,tal,head[MAX],flag[MAX],
 9     d[MAX],fa[MAX],ans[MAX];
10 void uni(int,int),addpoint(int);
11 int find(int);
12 int main(){
13     int x,y,k,n,m;
14     size=tal=0;
15     memset(flag,0,sizeof(flag));
16     memset(fa,-1,sizeof(fa));
17     scanf("%d %d",&n,&m);
18     for (int i=1;i<=m;i++){
19         scanf("%d %d",&x,&y);
20         uni(x,y);uni(y,x);
21     }
22     scanf("%d",&k);
23     for (int i=1;i<=k;i++){
24         scanf("%d",&d[i]);
25         flag[d[i]]=1;
26     }
27     for (int i=0;i<n;i++)
28         if (!flag[i]) addpoint(i);
29     ans[k+1]=tal;
30     for (int i=k;i>=0;i--){
31         addpoint(d[i]);
32         ans[i]=tal;
33     }
34     for (int i=1;i<=k+1;i++)
35         printf("%d\n",ans[i]);
36     return 0;
37 }
38 void uni(int x,int y){
39     size++;
40     edge[size].next=head[x];
41     head[x]=size;
42     edge[size].u=x;
43     edge[size].v=y;
44 }
45 void addpoint(int x){
46     int y,r;
47     tal++;fa[x]=x;
48     for (int e=head[x];e;e=edge[e].next){
49         y=edge[e].v;
50         if (fa[y]!=-1){
51             r=find(y);
52             if (x!=r){
53                 fa[r]=x;tal--;//据判据,一定要fa[r]=x
54             }
55         }
56     }
57 }
58 int find(int x){
59     if (fa[x]!=x) fa[x]=find(fa[x]);
60     return fa[x];
61 }
STD

 

posted on 2016-09-01 11:11  Absolutezero  阅读(193)  评论(0)    收藏  举报