12.食物链 并查集

 

 

 这是用并查集维护每个点和根节点的关系

只要我们知道了每个点和根节点的关系,就可以知道每两个点之间的关系

就和族谱一个道理,简单举个例子

假设族谱里最上面的那个人(根节点)是爷爷

然后A是爷爷(根节点)的儿子

B是爷爷(根节点)的孙子

那么就可以知道A和B的关系,A和B是父子

大致就是这个意思

然后这一题如何确定每个点和根节点的关系呢

由于是三种动物循环被吃

那么就用每个点到根节点的距离,来表示它和根节点的关系

我们说的这个距离,是这个点到根节点的真正的距离mod 3后的值,mod 3之后只会有3个值,0和1和2

如果某个点到根节点的距离mod 3是1的话,表示这个点可以吃根节点

如果某个点到根节点的距离mod 3是2的话,表示这个点可以被根节点吃

如果某个点到根节点的距离mod 3是0的话,表示这个点和根节点是同类

总结下来就是

mod 3 余 1的点,就是所有可以吃根节点的点、

mod 3 余 2的点,就是所有可以被根节点吃的点,也是所有可以吃mod 3 余 1的点

mod 3 余 0的点,就是所有和根节点同类的点,也是所有可以吃mod 3 余 2的点

根节点可以看成到自己的距离是0,所以就有

余0的吃余2,余2的吃余1,余1的吃余0

所以就可以把本题中的所有集合归为上面三大类

 如果说x吃y,y就是0,x就是1

吃1的就是2,z吃x,z就是2

吃2的就是3,3 mod 3 = 0,也就是0

k吃z,那k就是0

 总结下来就是用并查集维护每个点到根节点的距离

但是我们实际记录的是每个点到它的父节点的距离

 在做路径压缩时,再进行更新

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 50010;
 4 int p[N], d[N];
 5 //p存储父节点,d是距离
 6 int find(int x) {
 7     if (p[x] != x) { //如果x不是树根的话
 8         int t = find(p[x]); //t存储了根节点是谁
 9         d[x] += d[p[x]];
10         p[x] = t;
11     }
12     return p[x];
13 }
14 int main() {
15     int n, m;
16     cin >> n >> m;
17     for (int i = 1; i <= n; i++) {
18         p[i] = i; //初始化,每个点是一个集合,每个点到自己的距离d是0
19     }
20     int res = 0; //假话个数
21     while (m--) {
22         int t, x, y;
23         cin >> t >> x >> y;
24         if (x > n || y > n) {
25             res++;
26         } else {
27             int px = find(x), py = find(y);
28             if (t == 1) { //如果说x和y是同类
29                 if (px == py && (d[x] - d[y]) % 3 != 0) { //如果他们俩已经在一个树上了,用关系推理
30                     res++; 
31                 } else if (px != py) { //说明没在一个树上
32                     p[px] = py;
33                     d[px] = d[y] - d[x]; //见注解一
34                 }
35             } else {
36                 if (px == py && (d[x] - d[y] - 1) % 3 != 0) { //x吃y,x比y大一
37                     res++;
38                 } else if (px != py) {
39                     p[px] = py;
40                     d[px] = d[y] + 1 - d[x];
41                 }
42             }
43         }
44     }
45     cout << res << endl;
46     return 0;
47 }

注解一:

 

 当我们把?这个数填好之后,x和y是同类

那么在mod 3的意义下,d[x] + ? = d[y]

原文地址:https://www.cnblogs.com/fx1998/p/13299782.html