带权并查集(含种类并查集)【经典模板】 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug's life(简单) ③hihoCoder 1515 : 分数调查

带权并查集:

增加一个 value 值,并且每次合并和查找的时候需要去维护这个 value

例题一 :POJ 1182 食物链(经典)

题目链接:https://vjudge.net/contest/339425#problem/E

带权并查集的解法

定义两个数组fa[ ]和rela[ ],fa用来判断集合关系,rela用来描述其与根节点的关系。因为关系满足传递性,所以可以推导出给出条件下的当前关系,在判断与之前已有关系是否矛盾。

本题的解法巧妙地利用了模运算,rela数组用0表示同类,1表示当前点能吃别人,2表示当前点被别人吃。

再注意一点:在本题中需要注意的是传入的relation恰为描述的种类号减一。也就是说要提前将输入的描述号做-1处理后传入函数中

 1 #include <iostream>
 2 #include <stdio.h>
 3 using namespace std;
 4
 5 const int MAXN = 50005;
 6
 7 int fa[MAXN], rela[MAXN];
 8 int n, k, ans;
 9
10 void init()
11 {
12     for(int i = 1; i <= n; i++)
13     {
14         fa[i] = i;
15         rela[i] = 0;
16     }
17     ans = 0;
18 }
19
20 int find(int x)
21 {
22     if(x == fa[x])
23       return x;
24     else
25     {
26         int temp = fa[x];
27         fa[x] = find(fa[x]);
28         rela[x] = (rela[x] + rela[temp]) % 3;
29         return fa[x];
30     }
31 }
32
33 //以下的r均为处理过的relation,0表示同类,1表示x吃y,2表示x被y吃
34 //也就是说这里的r为题目所给编号-1
35 void merge(int r, int x, int y)
36 {
37     int fx = find(x), fy = find(y);
38     if(fx != fy)
39     {
40         fa[fx] = fy;
41         rela[fx] = (rela[y] - rela[x] + r + 3) % 3;//+3是为了防止这里相减产生负数
42     }
43 }
44
45 bool check(int r, int x, int y)
46 {
47    if(x > n || y > n)
48         return false;
49    if(r == 1 && x == y)
50     return false;
51    if(find(x) == find(y))
52    {
53        int relation = ((rela[x] - rela[y]) % 3 + 3) % 3;//根据前面正确描述得出的正确的关系
54        return relation == r;
55    }
56    else
57     return true;
58 }
59
60 int main()
61 {
62     scanf("%d%d", &n, &k);
63     init();
64     while(k--)
65     {
66         int a, b, c;
67         scanf("%d%d%d", &a, &b, &c);
68         a--;
69         if(check(a, b, c))
70             merge(a, b, c);
71         else
72             ans++;
73     }
74     printf("%d\n", ans);
75     return 0;
76 }

拆点并查集的解法可以看:https://www.cnblogs.com/-Ackerman/p/11779482.html

例题二 HDU - 1829 A bug’s life(简单)

题目链接:https://vjudge.net/contest/339425#problem/J

带权并查集解法
很明显和上面的思路相同,只不过由3种关系变成了2种关系
那么只需要将mod改为2 即可。

 1 #include <math.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <string>
 7 #include <string.h>
 8 #include <vector>
 9 #include <map>
10 #include <stack>
11 #include <set>
12 //#include <random>
13
14 #define LL long long
15 #define INF 0x3f3f3f3f
16 #define ls nod<<1
17 #define rs (nod<<1)+1
18 const int maxn = 2e5 + 10;
19 const double eps = 1e-9;
20
21 int pre[maxn],rel[maxn];
22 bool flag;
23
24 void init(int n) {
25     for (int i=0;i<=n;i++) {
26         pre[i] = i;
27         rel[i] = 0;
28     }
29     flag = false;
30 }
31
32 int find(int x) {
33     if (pre[x] != x) {
34         int t = pre[x];
35         pre[x] = find(pre[x]);
36         rel[x] = (rel[x] + rel[t]) % 2;
37     }
38     return pre[x];
39 }
40
41 void merge(int r,int x,int y) {
42     int rootx = find(x),rooty = find(y);
43     if (rootx != rooty) {
44         pre[rootx] = rooty;
45         rel[rootx] = (rel[y] - rel[x] + r + 2) % 2;
46     }
47 }
48
49 bool check(int r,int x,int y) {
50     int rootx = find(x),rooty = find(y);
51     if (rootx == rooty) {
52         int relation = (rel[x] - rel[y] + 2) % 2;
53         return relation == r;
54     }
55     else
56         return true;
57 }
58
59 int main() {
60     //freopen("../in.txt","r",stdin);
61     int T;
62     scanf("%d",&T);
63     int t = 1;
64     while (T--) {
65         int n,m;
66         scanf("%d%d",&n,&m);
67         init(n);
68         while (m--) {
69             int x,y;
70             scanf("%d%d",&x,&y);
71             if (check(1,x,y)) {
72                 merge(1,x,y);
73             }
74             else
75                 flag = true;
76         }
77         printf("Scenario #%d:\n",t++);
78         if (flag) {
79             printf("Suspicious bugs found!\n\n");
80         }
81         else
82             printf("No suspicious bugs found!\n\n");
83     }
84 }

例题三:hihoCoder 1515 : 分数调查

题目链接:https://vjudge.net/problem/HihoCoder-1515

思路:
同样使用带权并查集,用数组val记录同学们的权值(与根的分数差,比根高出多少分),那么
路径压缩时(find):val[x] = val[x] + val[temp];(temp为x的父节点)
合并时(merge): val[fx] = val[y] - val[x] + s (这里S是x->y的关系,符合公式)
那么要求x比y高多少分,直接输出 val[x] - val[y]即可。

 1 #include <math.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <string>
 7 #include <string.h>
 8 #include <vector>
 9 #include <map>
10 #include <stack>
11 #include <set>
12 //#include <random>
13
14 #define LL long long
15 #define INF 0x3f3f3f3f
16 #define ls nod<<1
17 #define rs (nod<<1)+1
18 const int maxn = 2e5 + 10;
19 const double eps = 1e-9;
20
21 int pre[maxn],val[maxn];
22
23 void init(int n) {
24     for (int i=0;i<=n;i++) {
25         pre[i] = i;
26         val[i] = 0;
27     }
28 }
29
30 int find(int x) {
31     if (pre[x] != x) {
32         int t = pre[x];
33         pre[x] = find(pre[x]);
34         val[x] += val[t];
35     }
36     return pre[x];
37 }
38
39 void merge(int x,int y,int v) {
40     int rootx = find(x),rooty = find(y);
41     if (rootx != rooty) {
42         pre[rootx] = rooty;
43         val[rootx] = val[y] - val[x] + v;
44     }
45 }
46
47 int main() {
48     //freopen("../in.txt","r",stdin);
49     int n,m,q;
50     scanf("%d%d%d",&n,&m,&q);
51     init(n);
52     for (int i=1;i<=m;i++) {
53         int x,y,v;
54         scanf("%d%d%d",&x,&y,&v);
55         merge(x,y,v);
56     }
57     while (q--) {
58         int x,y;
59         scanf("%d%d",&x,&y);
60         int rootx = find(x),rooty = find(y);
61         if (rootx == rooty) {
62             printf("%d\n",val[x] - val[y]);
63         }
64         else
65             printf("-1\n");
66     }
67     return 0;
68 }

当然后面两题也可以采用拆点并查集的解法可以参看这个博客:https://blog.csdn.net/floraqiu/article/details/79226320

带权并查集(含种类并查集)【经典模板】 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug's life(简单) ③hihoCoder 1515 : 分数调查

原文地址:https://www.cnblogs.com/-Ackerman/p/11780355.html

时间: 2024-10-06 11:57:32

带权并查集(含种类并查集)【经典模板】 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug's life(简单) ③hihoCoder 1515 : 分数调查的相关文章

hihoCoder 1515 分数调查(带权并查集)

http://hihocoder.com/problemset/problem/1515 题意: 思路: 带权并查集的简单题,计算的时候利用向量法则即可. 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int maxn = 100000+5; 5 6 int n,m,q; 7 int p[maxn],r[maxn]; 8 9 int finds(int x) 10 { 11 if(p[x

HihoCoder - 1515 分数调查 (带权并查集)

小Hi的学校总共有N名学生,编号1-N.学校刚刚进行了一场全校的古诗文水平测验. 学校没有公布测验的成绩,所以小Hi只能得到一些小道消息,例如X号同学的分数比Y号同学的分数高S分. 小Hi想知道利用这些消息,能不能判断出某两位同学之间的分数高低? Input 第一行包含三个整数N, M和Q.N表示学生总数,M表示小Hi知道消息的总数,Q表示小Hi想询问的数量. 以下M行每行三个整数,X, Y和S.表示X号同学的分数比Y号同学的分数高S分. 以下Q行每行两个整数,X和Y.表示小Hi想知道X号同学的

poj 1182 食物链 (带关系的并查集)

  食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 44835 Accepted: 13069 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同类.

hdu 1829 A Bug&#39;s Life (基础种类并查集)

先说说种类并查集吧. 种类并查集是并查集的一种.但是,种类并查集中的数据是分若干类的.具体属于哪一类,有多少类,都要视具体情况而定.当然属于哪一类,要再开一个数组来储存.所以,种类并查集一般有两个数组,一个存并查集内的父子关系,一个存各个节点所属的种类关系. 以这道题为例(题意在后面,如果没有读题,可以先看完题在来看这部分)—— 这道题很明显,将bug分成两类,一公一母.但是实际上我们并不关心它是公的还是母的,只关心它们之间是同性还是异性.所以,我们可以设与并查集的根节点同性的为0,反之为1.所

HDU 1829 A Bug&#39;s Life (种类并查集)

传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1829 A Bug's Life Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 19429    Accepted Submission(s): 6206 Problem Description Background Professor H

hdu 1829 A Bug&#39;s Life(分组并查集(偏移量))

A Bug's Life Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 9204    Accepted Submission(s): 2961 Problem Description Background Professor Hopper is researching the sexual behavior of a rare sp

又见关系并查集 以POJ 1182 食物链为例

简单的关系并查集一般很容易根据给出的关系搞出一个有向的环,那么两者之间的关系就变成了两者之间的距离. 对于此题: 若u,v不在一个集合内,则显然此条语句会合法(暂且忽略后两条,下同). 那么将fu 变为 fv的儿子时需加一条权值为 w 的边,w 满足(w + ru)%3 = (rv+ (D == 1? 0 : 1))%3(ru,rv分别为u,v与fv的关系,即距离). 之所以在D == 2时加 1,是因为u吃v表明着u到fv的距离比v到fv的距离大1. 同理,D == 1时,表明两者到fv的距离

POJ 2492 || HDU 1829:A Bug&#39;s Life(并查集)

传送门: POJ:点击打开链接 HDU:点击打开链接 A Bug's Life Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 27624   Accepted: 8979 Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they fe

POJ 1182 食物链【并查集】

题目链接:http://poj.org/problem?id=1182 此题利用并查集解决. 对于每只动物i创建3个元素i-A,i-B,i-C,并用这3*N个元素建立并查集. 1·i-x表示"i属于种类x" 2·并查集你的每一组表示组内所有元素代表的情况同时发生或不发生. 对于每一条信息,只需要按照下列操作即可: 1.第一种:x,y同类,合并x-A和y-A.x-B和y-B.x-C和y-C. 2.第二种:x吃y,,,合并x-A和y-B.x-B和y-C.x-C和y-A. 当然,在合并之前,