zoukankan      html  css  js  c++  java
  • ★★★[并查集变形] AcWing 240. 食物链 题解

    输入样例:

    100 7
    1 101 1 
    2 1 2
    2 2 3 
    2 3 3 
    1 1 3 
    2 3 1 
    1 5 5
    

    输出样例:

    3

     思路:

    我们可以将食物链的环状捕食关系用并查集的形式表现出来, 印射成某节点距根节点的距离取余3的值(0 /  1  /  2 ), 差值为1的即为捕食与被捕食的关系, 如 2 - > 1 - > 0 ->2表示的是2吃1, 1吃0(0可以吃2 )

    重点:

    1. 在压缩并查集时, 同时需要注意节点到根的距离d

    2. D=1时, 

    如果X, Y(此篇统一写作 a, b)均已纳入该生态系统(并查集合), 即find(a)==find(b) , 再判断他们与根的距离是否满足 da%3 - db%3 = 0 (化简为 (da-db)%3 == 0 )

    如果X, Y中有未纳入的,即find(a)!=find(b), 接下来我们需要将他们的根合并, 但这里与以往并查集合并不同的是, 不只要把他们的祖先合并, 还得维护与根的距离使得捕食关系(即取余3)不发生变化,

    我们不妨让pa(a的根) 等于pb, 此时要使a, b各自距根的距离取余3后

    相等,对照下图, 即(da+?-db)%3 == 0, 我们可以让 ? (即d[pa]) 满足 d[pa] = db-da

    D=2时, 与上面的思路大体相似

    如果X, Y(此篇统一写作 a, b)均已纳入该生态系统(并查集合), 即find(a)==find(b) , 再判断他们与根的距离是否满足 da%3 - db%3 = 1(即a吃b) (化简为 (da-db-1)%3 == 0 )

    如果X, Y中有未纳入的,即find(a)!=find(b), 接下来我们需要将他们的根合并, 但这里与以往并查集合并不同的是, 不只要把他们的祖先合并, 还得维护与根的距离使得捕食关系(即取余3)不发生变化,

    我们不妨让pa(a的根) 等于pb, 此时要使a, b各自距根的距离取余3后

    相等,对照下图, 即(da+?-db)%3 == 1 (化简为(da+?-db-1)%3 == 0), 我们可以让 ? (即d[pa]) 满足 d[pa] = db-da+1

    #include <iostream>
    using namespace std;
    
    const int N = 50010;
    int p[N], d[N]; //可食用关系,食物链等级(距根节点的距离取余后分为0,1,2三个等级)
    
    int find(int x)
    {
        if(p[x]!=x){
            int t = find(p[x]);
            d[x] += d[p[x]];
            p[x] = t;
        }
        return p[x];
    }
    
    int main()
    {
        int n,m;
        cin >> n >> m;
        
        for (int i = 1; i <= n; i ++ ) p[i] = i;
        
        int op, a, b;
        int res = 0;
        while (m -- )
        {
            cin >> op >> a >> b;
            
            if(a>n || b>n ) res ++;
            else
            {
                int pa = find(a), pb = find(b);
                if(op == 1){
                    if(pa==pb && (d[a]-d[b])%3)res ++;
                    else if(pa!=pb){
                        p[pa] = pb;
                        d[pa] = d[b] - d[a];
                    }
                }
                else{
                    if(pa==pb && (d[a]-d[b]-1)%3) res ++;
                    else if(pa!=pb){
                        p[pa] = pb;
                        d[pa] = d[b]-d[a]+1;
                    }
                }
            }
        }
        cout << res;
        return 0;
    }

  • 相关阅读:
    while,do while和for循环语句的用法
    阶乘
    java--测体重练习
    java---相亲练习
    java ---运算符
    java数据类型定义与输出
    基本Java数据类型
    揭开UTF-8的神秘面纱
    POJ 1164 城堡问题【DFS/位运算/种子填充法/染色法】
    POJ 3984 迷宫问题【BFS/路径记录/手写队列】
  • 原文地址:https://www.cnblogs.com/Knight02/p/15799062.html
Copyright © 2011-2022 走看看