[JSOI2008]星球大战

OJ题号:BZOJ1015、洛谷1197

思路:并查集。

将已经合并的结点拆开并不容易,因此可以考虑将此题倒着操作,把不连通的结点合并。

由题意得总共有n个结点,其中k个结点最终被删除,因此最终剩下的结点为n-k。

首先对这n-k个结点进行合并操作。然后将删除的点逆序加入图中,同时进行合并操作。每进行一次合法的合并操作就意味着减少一个联通块,同时要注意加入结点时,该结点本身也算一个新的联通块。

最后按原顺序输出每次的联通块个数。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<stack>
 5 const int N=400000;
 6 class UnionFindSet {
 7     private:
 8         int anc[N];
 9         int Find(int x) {
10             return (x==anc[x])?x:(anc[x]=Find(anc[x]));
11         }
12     public:
13         UnionFindSet(int n) {
14             for(int i=0;i<n;i++) anc[i]=i;
15         }
16         bool isConnected(int x,int y) {
17             return Find(x)==Find(y);
18         }
19         void Union(int x,int y) {
20             anc[Find(y)]=Find(x);
21         }
22 };
23 int main() {
24     int n,m;
25     scanf("%d%d",&n,&m);
26     std::vector<int> edge[n];
27     for(int i=0;i<m;i++) {
28         int x,y;
29         scanf("%d%d",&x,&y);
30         edge[x].push_back(y);
31         edge[y].push_back(x);
32     }
33     int k;
34     scanf("%d",&k);
35     std::stack<int> attack_list;
36     bool attacked[n];
37     memset(attacked,0,sizeof attacked);
38     for(int i=0;i<k;i++) {
39         int x;
40         scanf("%d",&x);
41         attack_list.push(x);
42         attacked[x]=true;
43     }
44     int ans=0;
45     UnionFindSet set(n);
46     for(int i=0;i<n;i++) {
47         if(!attacked[i]) {
48             ans++;
49             for(std::vector<int>::iterator j=edge[i].begin();j<edge[i].end();j++) {
50                 if(set.isConnected(i,*j)||attacked[*j]) continue;
51                 set.Union(i,*j);
52                 ans--;
53             }
54         }
55     }
56     std::stack<int> answers;
57     while(!attack_list.empty()) {
58         answers.push(ans);
59         ans++;
60         for(std::vector<int>::iterator i=edge[attack_list.top()].begin();i<edge[attack_list.top()].end();i++) {
61             if(set.isConnected(attack_list.top(),*i)||attacked[*i]) continue;
62             set.Union(attack_list.top(),*i);
63             ans--;
64         }
65         attacked[attack_list.top()]=false;
66         attack_list.pop();
67     }
68     answers.push(ans);
69     while(!answers.empty()) {
70         printf("%d
",answers.top());
71         answers.pop();
72     }
73     return 0;
74 }
原文地址:https://www.cnblogs.com/skylee03/p/6973511.html