合纵连横
时间限制:1000 ms | 内存限制:65535 KB
难度:3
- 描述
-
乱世天下,诸侯割据。每个诸侯王都有一片自己的领土。但是不是所有的诸侯王都是安分守己的,实力强大的诸侯国会设法吞并那些实力弱的,让自己的领土面积不断扩大。而实力弱的诸侯王为了不让自己的领土被吞并,他会联合一些其他同样弱小的诸侯国,组成联盟(联盟不止一个),来共同抵抗那些强大的诸侯国。 强大的诸侯国为了瓦解这些联盟,派出了最优秀的间谍来离间他们,使一些诸侯国退出联盟。最开始,每个诸侯国是一个联盟。
有两种操作
1、U x y 表示x和y在同一个联盟。(0≤x,y<n)
2、D x 表示x退出联盟。
- 输入
- 多组测试数据
第一行两个数,n和m(1 ≤ n≤ 10^5, 1 ≤ m ≤10^5),分别表示诸侯国的个数和操作次数。
接下来有m行操作 - 输出
- 输出联盟的个数
- 样例输入
-
5 7 U 0 1 U 1 2 U 0 3 D 0 U 1 4 D 2 U 0 2 10 1 U 0 9
- 样例输出
-
Case #1: 2 Case #2: 9
1 /** 2 分析:主要考察并查集中点的删除 3 算法: 4 Ⅰ、以前并查集是以其 1 - n 中的元素即作根节点又作子节点
5 《这样删除 pre [a] = n ++; 的话会使原先在一个区域的点可能不在一个区域了》 6 Ⅱ、现在我们将所有 1 - n 中的点作为子节点,n - 2n 的点作为根节点 7 《这样我们删除 pre [a] = 2n ++;的时候就不会打乱以前已在一个区域的点》 8 Ⅲ、其中 my_find()、my_join() 与以前并查集模板一致 9 10 关键代码: 11 void init () { 12 for (int i = 0; i < n; ++ i) 13 pre [i] = i + n; 14 for (int i = n; i < 2*n + m; ++ i) 15 pre [i] = i; 16 pos = 2*n; 17 return ; 18 ] 19 **/C/C++代码实现(AC):
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int n, m, pre [301005], pos; 6 7 void init () { 8 for (int i = 0; i < n; ++ i) 9 pre [i] = i + n; 10 for (int i = n; i < n + n + m; ++ i) 11 pre [i] = i; 12 pos = n + n; 13 return ; 14 } 15 16 int my_find (int x) { 17 int n1 = x; 18 while (n1 != pre [n1]) { 19 n1 = pre [n1]; 20 } 21 int i = x, j; 22 while (pre [i] != n1) { 23 j = pre [i]; 24 pre [i] = n1; 25 i = j; 26 } 27 return n1; 28 } 29 30 void my_join (int a, int b) { 31 int n1 = my_find (a), n2 = my_find (b); 32 if (n1 != n2) 33 pre [n1] = n2; 34 } 35 36 int main () { 37 int k = 1; 38 while (~scanf ("%d%d", &n, &m)) { 39 init (); 40 char c; 41 int a, b, ans = 0, temp [301005] = {0}; 42 for (int i = 0; i < m; ++ i) { 43 getchar (); 44 scanf ("%c", &c); 45 if (c == 'U') { 46 scanf ("%d%d", &a, &b); 47 my_join (a, b); 48 } 49 else { 50 scanf ("%d", &a); 51 pre [a] = pos ++; 52 } 53 } 54 55 for (int i = 0; i < n; ++ i) { // 查找有多少个区域 56 if (!temp [my_find (i)]) { // 在一个区域的有共同的根节点 57 temp [my_find (i)] = 1; 58 ++ ans; 59 } 60 } 61 printf ("Case #%d: %d ", k ++, ans); 62 } 63 }