南阳1022--合纵连横 (并查集+删点)

 

合纵连横

时间限制: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 }
 
原文地址:https://www.cnblogs.com/soTired/p/4732896.html