思路:离线倒序恢复被摧毁星球,同时维护联通块个数。但需要一定的优化。
具体:用邻接表存边。未被摧毁的星球记为现存;
第一次处理将未被摧毁的边连接(并查集),算出连通块个数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 }
浙公网安备 33010602011771号