题解:AcWing 240 食物链

【题目来源】

AcWing:240. 食物链 - AcWing题库

【题目描述】

动物王国中有三类动物 \(A\)\(B\)\(C\),这三类动物的食物链构成了有趣的环形。

\(A\)\(B\)\(B\)\(C\)\(C\)\(A\)

现有\(N\)个动物,以\(1\sim N\)编号。

每个动物都是\(A\)\(B\)\(C\)中的一种,但是我们并不知道它到底是哪一种。

有人用两种说法对这\(N\)个动物所构成的食物链关系进行描述:

第一种说法是 1 X Y,表示 \(X\)\(Y\) 是同类。

第二种说法是 2 X Y,表示 \(X\)\(Y\)

此人对\(N\)个动物,用上述两种说法,一句接一句地说出\(K\)句话,这\(K\)句话有的是真的,有的是假的。

当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

1.当前的话与前面的某些真的话冲突,就是假话;

2.当前的话中\(X\)\(Y\)\(N\)大,就是假话;

3.当前的话表示\(X\)\(X\),就是假话。

你的任务是根据给定的\(N\)\(K\)句话,输出假话的总数。

【输入】

第一行是两个整数\(N\)\(K\),以一个空格分隔。

以下\(K\)行每行是三个正整数\(D,X,Y\),两数之间用一个空格隔开,其中\(D\)表示说法的种类。

\(D=1\),则表示\(X\)\(Y\)是同类。

\(D=2\),则表示\(X\)\(Y\)

【输出】

只有一个整数,表示假话的数目。

【输入样例】

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

【输出样例】

3

【解题思路】

image

【算法标签】

《AcWing 240 食物链》 #并查集#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

const int N = 50010;  // 定义最大节点数

int n, m;      // n: 节点数量, m: 操作次数
int p[N];      // 并查集父节点数组
int d[N];      // 存储节点到父节点的距离(带权)

// 查找x的根节点(带路径压缩和距离更新)
int find(int x)
{
    if (p[x] != x) 
    {
        int u = find(p[x]);  // 递归找到根节点
        d[x] += d[p[x]];     // 更新当前节点到根节点的距离
        p[x] = u;            // 路径压缩
    }
    return p[x];
}

int main()
{
    scanf("%d%d", &n, &m);  // 输入节点数和操作数
  
    // 初始化并查集
    for (int i = 1; i <= n; i++)
        p[i] = i;
  
    int res = 0;  // 记录假话数量
  
    while (m--)   // 处理每个操作
    {
        int t, x, y;
        scanf("%d%d%d", &t, &x, &y);
      
        // 检查节点编号是否合法
        if (x > n || y > n) 
        {
            res++;  // 节点编号越界即为假话
        }
        else 
        {
            int px = find(x), py = find(y);
          
            if (t == 1)  // 操作1:x和y是同类
            {
                // 如果已在同一集合但距离差不是3的倍数(不是同类)
                if (px == py && (d[x] - d[y]) % 3)
                    res++;
                else if (px != py)  // 不同集合则合并
                {
                    p[px] = py;
                    d[px] = d[y] - d[x];  // 维护距离关系
                }
            }
            else  // 操作2:x吃y
            {
                // 如果已在同一集合但距离差不满足x吃y的关系
                if (px == py && (d[x] - d[y] - 1) % 3)
                    res++;
                else if (px != py)  // 不同集合则合并
                {
                    p[px] = py;
                    d[px] = d[y] + 1 - d[x];  // 维护距离关系
                }
            }
        }
    }
  
    printf("%d\n", res);  // 输出假话总数
    return 0;
}

【运行结果】

100 7
1 101 1
2 1 2
2 2 3
2 3 3 
1 1 3
2 3 1
1 5 5
3
posted @ 2026-02-21 19:53  团爸讲算法  阅读(2)  评论(0)    收藏  举报