Junk-Mail Filter 【并查集虚父节点】
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2473 题目大意: n个点,m个操作,操作时,输入M a b,表示a,b在一个集合里,输入S a 表示将a从集合里删除掉。求最后有多少个不同的集合。 解题思路: 需要删除结点,但是并非是删除与该节点为父亲节点的子树,而仅仅是该点。所以需要用到虚父节点。 所以再开一个数组,更新节点时直接改变当前节点的父节点,使其等于大于n的父节点,这样就把其节点删除了。 代码如下: 1 #include<iostream> 2 #include<string.h> 3 #define mem(a,b) memset(a,b,sizeof(a)) 4 using namespace std; 5 const int MAXN = 1e6 + 100; 6 7 int n,m,temp,k; 8 char op; 9 int p[MAXN],pre[MAXN],flag[MAXN]; 10 11 int find(int x) 12 { 13 if(pre[x] == x) 14 return x; 15 else 16 { 17 int root = find(pre[x]); 18 pre[x] = root; 19 return pre[x]; 20 } 21 } 22 23 int main() 24 { 25 cin.sync_with_stdio(false); 26 k = 1; 27 while(cin >> n >> m) 28 { 29 if(n == 0 && m == 0) 30 break; 31 temp = n,mem(flag,0); 32 for(int i = 0; i < n; i ++) 33 { 34 pre[i] = i; 35 p[i] = i; //虚设 36 } 37 for(int i = 1; i <= m; i++) 38 { 39 cin >> op; 40 if(op == ‘M‘) 41 { 42 int a,b; 43 cin >> a >> b; 44 int x = find(p[a]),y = find(p[b]); 45 if(x != y) 46 pre[y] = x; 47 } 48 else 49 { 50 int a; 51 cin >> a; 52 p[a] = temp; 53 pre[temp] = temp; 54 temp ++; 55 } 56 } 57 int ans = 0; 58 for(int i = 0; i < n; i ++) 59 { 60 int x = find(p[i]); 61 if(!flag[x]) 62 { 63 ans ++; 64 flag[x] = 1; 65 } 66 } 67 cout << "Case #" << k ++ << ": " << ans << endl; 68 } 69 return 0; 70 } ? 同样有一道一样题,更加直观。 乱世天下,诸侯割据。每个诸侯王都有一片自己的领土。但是不是所有的诸侯王都是安分守己的,实力强大的诸侯国会设法吞并那些实力弱的,让自己的领土 面积不断扩大。而实力弱的诸侯王为了不让自己的领土被吞并,他会联合一些其他同样弱小的诸侯国,组成联盟(联盟不止一个),来共同抵抗那些强大的诸侯国。 强大的诸侯国为了瓦解这些联盟,派出了最优秀的间谍来离间他们,使一些诸侯国退出联盟。最开始,每个诸侯国是一个联盟。 有两种操作 1、U x y 表示x和y在同一个联盟。(0≤x,y<n) 2、D x?? 表示x退出联盟。 仅仅是x退出联盟,对于其他的诸侯国没有影响。因此是删除单个点而不是子树。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |