题目链接:http://acm.fzu.edu.cn/problem.php?pid=2155
思路:在一般的并查集操作中设立虚父亲节点,当删除x的时候,不是真的删除x,而是通过一个映射,即令tmp[x] = cnt, parent[cnt] = cnt;这样x就从原来的集合中独立出来了,而我们每次合并x,y的时候,只需合并tmp[x], tmp[y]就可以了。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <set> 6 using namespace std; 7 8 const int MAXN = (2000000 +100); 9 int parent[MAXN], tmp[MAXN]; 10 bool mark[MAXN]; 11 int N, M, cnt; 12 13 void Init() 14 { 15 for (int i = 0; i < N; i++) { 16 parent[i] = tmp[i] = i; 17 } 18 } 19 20 int Find(int x) 21 { 22 if (parent[x] == x) { 23 return parent[x]; 24 } 25 return parent[x] = Find(parent[x]); 26 } 27 28 void Union(int x, int y) 29 { 30 int r1 = Find(x), r2 = Find(y); 31 if (r1 == r2) return; 32 if (r1 < r2) parent[r1] = r2; 33 else parent[r2] = r1; 34 } 35 36 int main() 37 { 38 int t = 1; 39 while (~scanf("%d %d", &N, &M)) { 40 if (N == 0 && M == 0) break; 41 Init(); 42 cnt = N; 43 while (M--) { 44 char str[2]; 45 int x, y; 46 scanf("%s", str); 47 if (str[0] == 'M') { 48 scanf("%d %d", &x, &y); 49 Union(tmp[x], tmp[y]); 50 } else if (str[0] == 'S') { 51 scanf("%d", &x); 52 parent[cnt] = cnt; 53 tmp[x] = cnt; 54 cnt++; 55 } 56 } 57 memset(mark, false, sizeof(mark)); 58 int ans = 0; 59 for (int i = 0; i < N; i++) { 60 if (!mark[Find(tmp[i])]) { 61 ans++; 62 mark[Find(tmp[i])] = true; 63 } 64 } 65 printf("Case #%d: %d ", t++, ans); 66 } 67 return 0; 68 }