zoukankan      html  css  js  c++  java
  • 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]

  • 相关阅读:
    Building a flexiable renderer
    Indirect Illumination in mental ray
    我的心情
    Cellular Automata
    Subsurface Scattering in mental ray
    Shader Types in mental ray
    BSP Traversal
    我的渲染器终于达到了MR的速度
    How to handle displacement and motion blur
    说明
  • 原文地址:https://www.cnblogs.com/fx1998/p/13299782.html
Copyright © 2011-2022 走看看