• 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]

  • 相关阅读:
    安装maven报错及解决
    Servlet包导入
    理解SQL SERVER的逻辑读,预读和物理读以及索引
    第六章(函数)编程题二
    第六章(函数)编程题一
    第五章(使用对象) 编程题一
    第三章(循环) 编程题 4
    第四章(数组) 编程题 1
    第三章(循环) 编程题 3
    低功耗蓝牙 ATT/GATT/Service/Characteristic 规格解读
  • 原文地址:https://www.cnblogs.com/fx1998/p/13299782.html
Copyright © 2020-2023  润新知