[kuangbin带你飞]之'并查集'专题

[kuangbin带你飞] 专题1-23 https://vjudge.net/article/187

 

专题五 并查集 
√ POJ 2236 Wireless Network  http://poj.org/problem?id=2236
√ POJ 1611 The Suspects  http://poj.org/problem?id=1611
√ HDU 1213 How Many Tables  http://acm.hdu.edu.cn/showproblem.php?pid=1213
hdu炸了。 HDU 3038 How Many Answers Are Wrong  http://acm.hdu.edu.cn/showproblem.php?pid=3038
√ POJ 1182 食物链  http://poj.org/problem?id=1182
POJ 1417 True Liars  http://poj.org/problem?id=1417
√ POJ 1456 Supermarket  http://poj.org/problem?id=1456
√ POJ 1733 Parity game  http://poj.org/problem?id=1733
√ POJ 1984 Navigation Nightmare  http://poj.org/problem?id=1984
√ POJ 2492 A Bug's Life  http://poj.org/problem?id=2492
√ POJ 2912 Rochambeau  http://poj.org/problem?id=2912
ZOJ 3261 Connections in Galaxy War  http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261
√ HDU 1272 小希的迷宫  http://acm.hdu.edu.cn/showproblem.php?pid=1272
√ POJ 1308 Is It A Tree?  http://poj.org/problem?id=1308

 // 种类并查集

// 种类并查集关系数组的向量偏移量 理解↓

// 图片来源 https://blog.csdn.net/u010660276/article/details/24851367

[kuangbin带你飞]之'并查集'专题_第1张图片

 

 

poj 2492 A Bug's Life http://poj.org/problem?id=2492

// 题意:每次给出两个昆虫的关系(异性关系),然后发现这些条件中是否有悖论 

如 :input

    1 2

    2 3

    1 3   ->错的

 1 #include
 2 
 3 const int MAXN = 2000+5;
 4 
 5 int fa[MAXN], re[MAXN];//  re[i] 存 i和他根节点的关系   0为同性 1为异性
 6 
 7 inline int find(int x) {
 8     if(x != fa[x]) {
 9         int t = fa[x];
10         fa[x] = find(fa[x]);
11         re[x] = (re[x] + re[t]) % 2;// 更新x与根节点的关系
12     }
13     return fa[x];
14 }
15 
16 int main() {
17     int T;
18     int cnt = 0;
19     scanf("%d", &T);
20     while(T--) {
21         int n, m;
22         int x, y;
23         bool flag = true;
24         scanf("%d%d", &n, &m);
25         for(int i = 1; i <= n; ++i) { fa[i] = i; re[i] = 0; }
26         for(int i = 0; i != m; ++i) {
27             scanf("%d%d", &x, &y);
28             if(!flag) continue;
29             int x_fa = find(x);
30             int y_fa = find(y);
31             if(x_fa != y_fa) {
32                 fa[x_fa] = y_fa;
33                 re[x_fa] = (-re[x] + 1 + re[y] + 2) % 2;// 此处和37行中加2 都是为了消除0的影响
36             }
37             else if((re[x] - re[y] + 2) % 2 == 0) flag = false;
38         }
39         printf("Scenario #%d:\n", ++cnt);
40         if(flag) printf("No suspicious bugs found!\n\n");
41         else printf("Suspicious bugs found!\n\n");
42     }
43     return 0;
44 }

 [kuangbin带你飞]之'并查集'专题_第2张图片

 

 

 // 同理给出poj 1182 代码

 1 #include
 2 #include
 3 using namespace std;
 4 
 5 const int MAXN = 50000+5;
 6 
 7 int fa[MAXN], re[MAXN];
 8 
 9 inline int find(int x) {
10     if(x != fa[x]) {
11         int t = fa[x];
12         fa[x] = find(fa[x]);
13         re[x] = (re[x] + re[t]) % 3;
14     }
15     return fa[x];
16 }
17 
18 int main() {
19     int n, k;
20     int ans = 0;
21     scanf("%d%d", &n, &k);
22     for(int i = 1; i <= MAXN; ++i) { fa[i] = i; re[i] = 0; }
23     
24     int com;
25     int x, y;
26     int xf, yf;
27     for(int i = 0; i != k; ++i) {
28         scanf("%d%d%d", &com, &x, &y);
29         if(x > n || y > n || com == 2 && x == y) { ans++; continue; }
30         xf = find(x);
31         yf = find(y);
32         if(xf != yf) {
33             fa[xf] = yf;
34             re[xf] = (-re[x] + com-1 + re[y] + 3) % 3;
35         }
36         else if((re[x] - re[y] + 3) % 3 != com - 1) ans++;
37     }
38     printf("%d\n", ans);
39     return 0;
40 }
View Code

 

 


// 区间种类并查集

// poj1733 http://poj.org/problem?id=1733

// 有n个结点,给出了m个操作,操作是 a b com 表示结点a到结点b的和是奇数或偶数,输出前多少个操作是正确的
// n <= 1000000000; m <= 5000
// n 很大 m不大 由于有用的数据只是询问给出的 所以与n关系不大,所以离散化--没询问的点不管他(因为数组可能也开不到1000000000
)
 1 #include
 2 #include
 3 #include
 4 using namespace std;
 5 
 6 const int MAXN = 5000+5;
 7 
 8 int l[MAXN], r[MAXN];
 9 char com[MAXN][10];
10 int cnt, fa[2*MAXN], re[2*MAXN];
11 map<int, int> mp;
12 
13 inline int find(int x) {
14     if(x != fa[x]) {
15         int t = fa[x];
16         fa[x] = find(fa[x]);
17         re[x] = (re[x] + re[t]) % 2;
18     }
19     return fa[x];
20 }
21 
22 int main() {
23     int n, m;
24     scanf("%d%d", &n, &m);
25     cnt = 0;
26     for(int i = 0; i != m; ++i) {
27         scanf("%d%d%s", &l[i], &r[i], com[i]);
28         l[i]--;// 因为a要加到b 如果 a==b: a到b的1的个数是1 但是由于a==b fa[a] == fa[b] 那么re[a](到根节点b)就无法更新了(则a~b的1的个数为0),显然不对
// 上面是自己理解的 其实区间并查集 关系区间都要取一开一闭 如:(a, b] || [a, b)
29 if(!mp[l[i]]) mp[l[i]] = ++cnt; 30 if(!mp[r[i]]) mp[r[i]] = ++cnt; 31 } 32 for(int i = 1; i <= cnt; ++i) { fa[i] = i; re[i] = 0; } 33 34 int x, y, c; 35 int xf, yf; 36 int t = m; 37 for(int i = 0; i != m; ++i) { 38 x = mp[l[i]]; 39 y = mp[r[i]]; 40 if(com[i][0] == 'e') c = 0; 41 else c = 1; 42 xf = find(x); 43 yf = find(y); 44 if(xf != yf) { 45 fa[xf] = yf; 46 re[xf] = (-re[x] + c + re[y] + 2) % 2; 47 } 48 else if((re[x] - re[y] + 2) % 2 != c) { 49 t = i; 50 break; 51 } 52 } 53 printf("%d\n", t); 54 return 0; 55 }

 


 

//奇葩并查集 poj 1984 http://poj.org/problem?id=1984

//此题 输入输出比较恶心  我英语不好只能瞎猜题意

 1 #include
 2 #include
 3 #include
 4 using namespace std;
 5 const int MAXN = 40000+5;
 6 
 7 struct Query {
 8     int x, y, id;// 存询问的列表(输入进去的东西)
 9     int dis;// x与y之间的距离
10     int no;// 第几个输入的(输出要按输入顺序输出)
11 } q[10005] ;
12 
13 int fa[MAXN], re[MAXN][2];// 带权并查集 [][2]是为了存x方向和y方向
14 int l[MAXN], r[MAXN], v[MAXN];// 输入的三个参数
15 char c[MAXN];// 输入的方向(N S W E)
16 
17 inline int find(int x) {
18     if(x != fa[x]) {
19         int t = fa[x];
20         fa[x] = find(fa[x]);
21         re[x][0] += re[t][0];
22         re[x][1] += re[t][1];
23     }
24     return fa[x];
25 }
26 
27 bool cmp(const Query a, const Query b) {
28     return a.id < b.id;
29 }
30 
31 bool cmp2(const Query a, const Query b) {
32     return a.no < b.no;
33 }
34 
35 int main() {
36     int n, m;
37     scanf("%d%d", &n, &m);
38     for(int i = 1; i <= n; ++i) { fa[i] = i; re[i][0] = re[i][1] = 0; }
39     for(int i = 0; i != m; ++i) {
40         scanf("%d%d%d", &l[i], &r[i], &v[i]);
41         getchar(); scanf("%c", &c[i]);
42     }
43     int k;
44     scanf("%d", &k);
45     for(int i = 0; i != k; ++i) {
46         scanf("%d%d%d", &q[i].x, &q[i].y, &q[i].id);
47         q[i].no = i;
48     }
49     sort(q, q+k, cmp);
50     int x, y;
51     int xf, yf;
52     char com;
53     int t = 0;
54     for(int i = 0; i != m; ++i) {
55         x = l[i]; y = r[i]; com = c[i];
56         xf = find(x);
57         yf = find(y);
58         if(xf != yf) {
59             fa[xf] = yf;
60             re[xf][0] = -re[x][0] + re[y][0];
61             re[xf][1] = -re[x][1] + re[y][1];
62             if(com == 'N') { re[xf][0] +=  0; re[xf][1] +=  v[i]; }
63             if(com == 'S') { re[xf][0] +=  0; re[xf][1] += -v[i]; }
64             if(com == 'W') { re[xf][0] += -v[i]; re[xf][1] +=  0; }
65             if(com == 'E') { re[xf][0] +=  v[i]; re[xf][1] +=  0; }
66         }
67         while(i+1 == q[t].id) {// 必须用while (Bob询问的时候可能同一时间段问几个问题)
68             if(find(q[t].x) != find(q[t].y)) q[t].dis = -1;
69             else q[t].dis = abs(re[q[t].x][0] - re[q[t].y][0]) + abs(re[q[t].x][1] - re[q[t].y][1]);
70             t++;
71         }
72     }
73     sort(q, q+k, cmp2);
74     for(int i = 0; i != k; ++i) {
75         printf("%d\n", q[i].dis);
76     }
77     return 0;
78 }

 

 // poj 2912 关系并查集+枚举 http://poj.org/problem?id=2912

 1 #include
 2 #include
 3 #include<set>
 4 using namespace std;
 5 
 6 const int MAXN = 500+5;
 7 
 8 int fa[MAXN], re[MAXN];
 9 int l[4*MAXN], r[4*MAXN], com[4*MAXN];
10 
11 inline int find(int x) {
12     if(x != fa[x]) {
13         int t = fa[x];
14         fa[x] = find(fa[x]);
15         re[x] = (re[x] + re[t]) % 3;
16     }
17     return fa[x];
18 }
19 
20 int main() {
21     int n, m;
22     while(scanf("%d%d", &n, &m) == 2) {
23         char ch[2*MAXN];
24         for(int i = 0; i != m; ++i) { l[i] = r[i] = 0; }
25         for(int i = 0; i != m; ++i) {
26             scanf("%s", ch);
27             int j = 0;
28             while(ch[j] >= '0' && ch[j] <= '9') {
29                 l[i] = l[i]*10 + ch[j]-'0';
30                 j++;
31             }
32             if(ch[j] == '=') com[i] = 0;
33             else if(ch[j] == '>') com[i] = 1;
34             else com[i] = 2;
35             j++;
36             while(ch[j] != '\0') {
37                 r[i] = r[i]*10 + ch[j]-'0';
38                 j++;
39             }
40         }
41         int x, y;
42         int xf, yf;
43         int c;
44         int pos = 0;
45         set<int> ct;
46         for(int k = 0; k != n; ++k) {
47             bool flag = true;
48             int cnt = 0;
49             for(int qwq = 0; qwq != n; ++qwq) { fa[qwq] = qwq; re[qwq] = 0; }
50             for(int i = 0; i != m; ++i) {
51                 if(l[i] == k || r[i] == k) continue;
52                 x = l[i]; y = r[i]; c = com[i];
53                 xf = find(x);
54                 yf = find(y);
55                 if(xf != yf) {
56                     fa[xf] = yf;
57                     re[xf] = (-re[x] + c + re[y] + 3) % 3;
58                 }
59                 else if((re[x] - re[y] + 3) % 3 != c) {
60                     flag = false;
61                     pos = max(pos, i+1);// 想不到这个(排除法 有一个裁判且其他人都不是裁判的时候 就能确定他是裁判)
62                     break;
63                 }
64             }
65             if(flag) ct.insert(k);
66         }
67         if(ct.size() == 0) printf("Impossible\n");
68         else if(ct.size() == 1) {
69             int t = *ct.begin();
70             printf("Player %d can be determined to be the judge after %d lines\n", t, pos);
71         }
72         else printf("Can not determine\n");
73     }
74     return 0;
75 }

 

//poj 1456 贪心(这题并查集优化完全没必要)http://poj.org/problem?id=1456

 1 #include
 2 #include
 3 #include
 4 using namespace std;
 5 
 6 const int MAXN = 10000+5;
 7 
 8 struct Product {
 9     int v, r;
10 } p[MAXN];
11 
12 bool cmp(const Product a, const Product b) {
13     if(a.v != b.v) return a.v > b.v;
14     return a.r > b.r;
15 }
16 
17 int fa[MAXN];
18 inline int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
19 
20 inline void init() {
21     for(int i = 0; i != MAXN; ++i) {
22         fa[i] = i;
23     }
24 }
25 int n;
26 int ans;
27 
28 int main() {
29     while(scanf("%d", &n) == 1) {
30         for(int i = 0; i != n; ++i) {
31             scanf("%d%d", &p[i].v, &p[i].r);
32         }
33         sort(p, p+n, cmp);
34         ans = 0;
35         init();
36         for(int i = 0; i != n; ++i) {
37             int d = p[i].r;
38             int x = find(d);
39             if(x > 0) {
40                 fa[x] = x-1;
41                 ans += p[i].v;
42             }
43         }
44         printf("%d\n", ans);
45     }
46     return 0;
47 }
View Code

 

// hdu 1272 & poj 1308

// "求树是否是个环"(简单并查集) ,水。

 1 #include
 2 #include
 3 using namespace std;
 4 
 5 const int MAXN = 1e3+5;
 6 
 7 inline int read() {
 8     char c = getchar(); int s = 0, f = 1;
 9     while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
10     while(c >= '0' && c <= '9')  s = s*10 + c-'0', c = getchar();
11     return s*f;
12 }
13 
14 int p[MAXN];
15 
16 inline int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
17 
18 int main() {
19     int s, e;
20     int T = 1;
21     while(1) {
22         bool flag = true;
23         while(1) { //scanf("%d%d", &s, &e) == 2 && s
24             s = read(), e = read();
25             if(s == 0 && e == 0) break;
26             if(s == -1) return 0;
27             if(!p[s]) p[s] = s;
28             if(!p[e]) p[e] = e;
29             int x = find(s);
30             int y = find(e);
31             if(x == y) flag = false;
32             else p[x] = y;
33         }
34         int ans = 0;
35         for(int i = 1; i <= MAXN; ++i) {
36             if(p[i] == i) ans++;
37             p[i] = 0;
38         }
39 
40         printf("Case %d is ", T++);
41         if(!flag || ans > 1) printf("not a tree.\n");
42         else printf("a tree.\n");
43     }
44     return 0;
45 }
View Code

 

 // poj 2236 简单并查集 水。

 1 #include
 2 #include
 3 #include
 4 using namespace std;
 5 
 6 const int MAXN = 1000+5;
 7 
 8 struct node {
 9     double x, y;
10     int fa;
11     bool repair;
12 } p[MAXN];
13 
14 inline double get_dis(int x, int y) {
15     return sqrt((p[x].x-p[y].x)*(p[x].x-p[y].x) + (p[x].y-p[y].y)*(p[x].y-p[y].y));
16 }
17 
18 inline int find(int x) { return p[x].fa == x ? x : p[x].fa = find(p[x].fa); }
19 
20 int main() {
21     int n, d;
22     scanf("%d%d", &n, &d);
23     for(int i = 1; i <= n; ++i) {
24         scanf("%lf%lf", &p[i].x, &p[i].y);
25         p[i].fa = i;
26         p[i].repair = false;
27     }
28     getchar();
29     char c;
30     while(scanf("%c", &c) == 1) {
31         if(c == 'O') {
32             int x;
33             scanf("%d", &x);
34             for(int i = 1; i <= n; ++i) {
35                 if(p[i].repair) {
36                     if(get_dis(i, x) <= d*1.0) {
37                         int xf = find(x);
38                         int yf = find(i);
39                         if(xf != yf) p[xf].fa = yf;
40                     }
41                 }
42             }
43             p[x].repair = true;
44         }
45         else {
46             int x, y;
47             scanf("%d%d", &x, &y);
48             if(find(x) == find(y)) printf("SUCCESS\n");
49             else printf("FAIL\n");
50         }
51         getchar();
52     }
53     return 0;
54 }
View Code

 

// poj 1611 简单并查集 水。

 1 #include
 2 #include
 3 using namespace std;
 4 
 5 const int MAXN = 3e4+5;
 6 
 7 int p[MAXN];
 8 inline int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
 9 
10 int main() {
11     int n, m;
12     while(scanf("%d%d", &n, &m) == 2 && n) {
13         memset(p, -1, sizeof(p));
14         p[0] = 0;
15         for(int i = 0; i != m; ++i) {
16             int num, x, t;
17             scanf("%d", &num);
18             for(int j = 0; j != num; ++j) {
19                 scanf("%d", &x);
20                 if(p[x] == -1) p[x] = x; 
21                 if(j != 0) {
22                     int xf = find(x);
23                     int tf = find(t);
24                     if(xf != tf) p[xf] = tf;
25                 }
26                 t = x;
27             }
28         }
29         int ans = 0;
30         for(int i = 0; i != n; ++i) {
31             //printf("%d\n", find(i));
32             if(p[i] != -1 && find(i) == find(0)) ans++;
33         }
34         printf("%d\n", ans);
35     }
36     return 0;
37 }
View Code

 

// poj 1988 带权并查集入门题 http://poj.org/problem?id=1988

 1 #include
 2 #include
 3 using namespace std;
 4 
 5 const int MAXN = 30000+5;
 6 
 7 int fa[MAXN], dis[MAXN], sum[MAXN];
 8 
 9 inline int find(int x) {
10     if(x != fa[x]) {
11         int t = fa[x];
12         fa[x] = find(fa[x]);
13         dis[x] += dis[t];
14     }
15     return fa[x];
16 }
17 
18 inline void Union(int x, int y) {
19     x = find(x);
20     y = find(y);
21     if(x != y) {
22         fa[x] = y;
23         dis[x] = sum[y];
24         sum[y] += sum[x];
25     }
26 }
27 
28 int main() {
29     int n, x, y;
30     char c;
31     scanf("%d", &n);
32     for(int i = 0; i != MAXN; ++i) {
33         fa[i] = i;
34         dis[i] = 0;
35         sum[i] = 1;
36     }
37     for(int i = 0; i != n; ++i) {
38         getchar();
39         scanf("%c", &c);
40         if(c == 'M') {
41             scanf("%d%d", &x, &y);
42             Union(x, y);
43         }
44         else {
45             scanf("%d", &x);
46             find(x);
47             printf("%d\n", dis[x]);
48         }
49     }
50     return 0;
51 }
View Code

 

 

你可能感兴趣的:([kuangbin带你飞]之'并查集'专题)