P1197 星球大战(并查集+链式向前星)

 1 #include<iostream>
 2 using namespace std;
 3 const int N=4e5+100;
 4 struct edge
 5 {
 6     int from;
 7     int to;
 8     int nex;
 9 };
10 edge a[N];
11 int head[N];
12 int cnt=0;
13 //以上是链式向前星存储图
14 int fa[N];//并查集
15 bool used[N];//每个点是否被摧毁
16 int node[N];//被摧毁的
17 int ans[N];//答案
18 void init(int n)
19 {
20     for(int i=0;i<n;i++)
21     {
22         fa[i]=i;//并查集
23         used[i]=0;
24         head[i]=-1;
25     }
26 }
27 void add(int b,int c)//边的计数从0开始
28 {
29     a[cnt].from=b;
30     a[cnt].to=c;
31     a[cnt].nex=head[b];
32     head[b]=cnt;
33     cnt++;
34 }
35 int finds(int x)
36 {
37     while(fa[x]!=fa[fa[x]])
38     {
39         fa[x]=fa[fa[x]];
40     }
41     return fa[x];
42 }
43 int main(void)
44 {
45     int n,m;
46     cin>>n>>m;
47     init(n);//初始化
48     for(int i=1;i<=m;i++)
49     {
50         int a,b;
51         cin>>a>>b;
52         add(a,b);//无向图
53         add(b,a);
54     }
55     int k;
56     cin>>k;
57     for(int i=0;i<k;i++)//被摧毁的顺序,反过来就是重建的顺序
58     {
59         cin>>node[i];
60         used[node[i]]=1;//标记为已打击
61     }
62     int total=n-k;//假设全部的边都不存在,那么所有打击完成之后,所剩的联通分量就是n-k
63                     //以下计算打击完成后的连通分量数
64     for(int i=0;i<2*m;i++)//遍历所有的边
65     {
66         if(used[a[i].from]==0&&used[a[i].to]==0)//如果都没有被打击
67         {
68             if(finds(a[i].from)!=finds(a[i].to))//且在此前没有被连接在一起
69             {
70                 total--;
71                 fa[finds(a[i].from)]=finds(a[i].to);
72             }
73         }
74     }
75     ans[k]=total;
76     for(int i=k-1;i>=0;i--)
77     {
78         int t=node[i];
79         total++;
80         used[t]=0;//已修复,没有被打击
81         for(int i=head[t];i!=-1;i=a[i].nex)//遍历修复的点的全部边
82         {
83             if(used[a[i].to]==0&&finds(t)!=finds(a[i].to))//如果可以连而且还没连
84             {
85                 total--;
86                 fa[finds(t)]=finds(a[i].to);
87             }
88         }
89         ans[i]=total;
90     }
91     for(int i=0;i<=k;i++)
92     {
93         cout<<ans[i]<<endl;
94     }
95     return 0;
96 }

让你确定每次打击之后还有多少个联通分量(并查集似乎顺着做不了),就只有逆着来做了

首先假设所有将要打击的点都被破坏,然后再一步一步重建,这就是正常的并查集了,但是链式向前星挺难的

原文地址:https://www.cnblogs.com/greenofyu/p/12256086.html