合纵连横
时间限制: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
- 上传者
- ACM_马振阳
- RE: 上午周赛出的这道题, 当时写了一半就发现不太对, 下午一看, 果然略坑;
- 并查集删点操作对于孩子节点来说, 直接father[i] = i; 就可以了。 根节点不能用这种方法,所以就建立一个新数组。
- 相当于把原来数组包含在里面一块进行操作, 根节点合并时 对新数组操作, 原来数组节点的删除也不会影响已经建立的关系。 删除的节点存为虚点,http://blog.csdn.net/a915800048/article/details/41703865
-
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 int father[100010], set[100010 * 2], vis[100010 * 2]; 6 int n, m; 7 void init() 8 { 9 for(int i = 0; i < n; i++) 10 { 11 father[i] = i; 12 set[i] = i; 13 } 14 } 15 int find(int a) 16 { 17 int r, j, k; 18 r = a; 19 while(r != set[r]) 20 r = set[r]; 21 j = a; 22 while(j != r) 23 { 24 k = set[j]; 25 set[j] = r; 26 j = k; 27 } 28 return r; 29 } 30 void mercy(int a, int b) 31 { 32 int q = find(a); 33 int p = find(b); 34 if(q != p) 35 set[q] = p; 36 } 37 int main() 38 { 39 int temp = 1; 40 while(~scanf("%d %d", &n, &m)) 41 { 42 init(); 43 int dis = n; //虚点; 44 for(int i = 0; i < m; i++) 45 { 46 char str[2]; 47 scanf("%s", str); 48 if(str[0] == 'U') 49 { 50 int a, b; 51 scanf("%d %d", &a, &b); 52 mercy(father[a], father[b]); 53 } 54 else 55 { 56 int c; 57 scanf("%d", &c); 58 father[c] = dis; 59 set[dis] = dis; 60 dis++; 61 } 62 } 63 int ans = 0; 64 memset(vis, 0, sizeof(vis)); 65 for(int i = 0; i < n; i++) 66 { 67 if(!vis[find(father[i])]) 68 { 69 //printf("%d %d %d ", set[i], father[i], find(father[i])); 70 vis[find(father[i])] = 1; 71 ans++; 72 } 73 } 74 printf("Case #%d: %d ", temp++, ans); 75 } 76 return 0; 77 }