hdu 2473 Junk-Mail Filter (暴力并查集)

Problem - 2473

  为什么标题写的是暴力并查集?因为我的解法跟网上的有所不同,方法暴力很多。

  先解释题意,这是一个模拟处理垃圾邮件的问题。垃圾邮件要根据它们的性质进行分类。对于10w个邮件,操作M是这两个邮件具有相同的属性,属性是可以传递的,也就是说,1和2有相同属性,2和3有相同属性,那么1和3就有相同属性。操作S是将这个邮件分离出来,不和任何的邮件有相同属性。最后问不同属性的邮件有多少种。这么看来,这是一个并查集。网上的正解,是把那个删除的结点当成虚拟结点,继续放在那里。然后重新开一个新的结点来存放分离出来的结点。

  而我的做法则是直接构造并查集树,我的树是会记录子结点有那些的,更新的时候就只能直接暴力更新了。

代码如下:

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <set>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <stack>
  7 
  8 using namespace std;
  9 
 10 const int N = 111111;
 11 stack<int> tmp;
 12 
 13 struct MFS {
 14     set<int> sn[N];
 15     int fa[N];
 16     void init() { for (int i = 0; i < N; i++) fa[i] = i, sn[i].clear(), sn[i].insert(i);}
 17     int find(int x) {
 18         while (!tmp.empty()) tmp.pop();
 19         while (fa[x] != x) {
 20             tmp.push(x);
 21             sn[fa[x]].erase(x);
 22             x = fa[x];
 23         }
 24         while (!tmp.empty()) {
 25             fa[tmp.top()] = x;
 26             sn[x].insert(tmp.top());
 27             tmp.pop();
 28         }
 29         return x;
 30     }
 31     void merge(int x, int y) {
 32         int fx = find(x), fy = find(y);
 33         if (fx == fy) return ;
 34         sn[fa[fy]].erase(fy);
 35         fa[fy] = fx;
 36         sn[fx].insert(fy);
 37     }
 38     void reset(int x) {
 39         set<int>::iterator si = sn[x].begin();
 40         if (fa[x] == x) {
 41             if (*si == x) si++;
 42             if (si == sn[x].end()) return ;
 43             int t = *si;
 44             fa[t] = t;
 45             sn[t].insert(t);
 46             si++;
 47             while (si != sn[x].end()) {
 48                 if (*si == x) { si++; continue;}
 49                 fa[*si] = t;
 50                 sn[t].insert(*si);
 51                 si++;
 52             }
 53         } else {
 54             int fx = find(x);
 55             sn[fx].erase(x);
 56             while (si != sn[x].end()) {
 57                 fa[*si] = fx;
 58                 sn[fx].insert(*si);
 59                 si++;
 60             }
 61         }
 62         fa[x] = x;
 63         sn[x].clear();
 64         sn[x].insert(x);
 65     }
 66 } mfs;
 67 bool vis[N];
 68 
 69 int main() {
 70 //    freopen("in", "r", stdin);
 71     int n, m, x, y, cas = 1;
 72     char op[3];
 73     while (~scanf("%d%d", &n, &m) && (n || m)) {
 74         mfs.init();
 75         for (int i = 0; i < m; i++) {
 76             scanf("%s", op);
 77             if (op[0] == 'M') {
 78                 scanf("%d%d", &x, &y);
 79                 //mfs.reset(y);
 80                 mfs.merge(x, y);
 81             } else {
 82                 scanf("%d", &x);
 83                 mfs.reset(x);
 84             }
 85 //            for (int i = 0; i < 3; i++) cout << mfs.fa[i] << ' '; cout << endl;
 86         }
 87         memset(vis, 0, sizeof(vis));
 88         int cnt = 0;
 89         for (int i = 0, t; i < n; i++) {
 90             t = mfs.find(i);
 91             if (vis[t]) continue;
 92             cnt++;
 93             vis[t] = true;
 94         }
 95         printf("Case #%d: %d
", cas++, cnt);
 96     }
 97     return 0;
 98 }
 99 
100 /*
101 5 6
102 M 0 1
103 M 1 2
104 M 1 3
105 S 1
106 M 1 2
107 S 3
108 
109 3 4
110 M 1 2
111 M 0 1
112 S 1
113 S 0
114 
115 0 0
116 */
View Code

  用虚拟结点的方法将会尽快更新。

 

 

——written by Lyon

原文地址:https://www.cnblogs.com/LyonLys/p/hdu_2473_Lyon.html