• 食物链解读


    [NOI2001] 食物链

    题目描述

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

    现有 N N N 个动物,以 1 ∼ N 1 \sim N 1N 编号。每个动物都是 A , B , C A,B,C A,B,C 中的一种,但是我们并不知道它到底是哪一种。

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

    • 第一种说法是 1 X Y,表示 X X X Y Y Y 是同类。
    • 第二种说法是2 X Y,表示 X X X Y Y Y

    此人对 N N N 个动物,用上述两种说法,一句接一句地说出 K K K 句话,这 K K K 句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

    • 当前的话与前面的某些真的话冲突,就是假话;
    • 当前的话中 X X X Y Y Y N N N 大,就是假话;
    • 当前的话表示 X X X X X X,就是假话。

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

    输入格式

    第一行两个整数, N , K N,K N,K,表示有 N N N 个动物, K K K 句话。

    第二行开始每行一句话(按照题目要求,见样例)

    输出格式

    一行,一个整数,表示假话的总数。

    样例 #1

    样例输入 #1

    100 7
    1 101 1
    2 1 2
    2 2 3
    2 3 3
    1 1 3
    2 3 1
    1 5 5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    样例输出 #1

    3
    
    • 1

    提示

    对于全部数据, 1 ≤ N ≤ 5 × 1 0 4 1\le N\le 5 \times 10^4 1N5×104 1 ≤ K ≤ 1 0 5 1\le K \le 10^5 1K105

    这是一道没本事的中等题,看过的人都知道用指针做。不过在实操的过程中有几个小点需要注意:
    先看代码:

    #include
    #include
    using namespace std;
    const int N=50010;
    int  n,k,res;
    int p[N],d[N];
    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()
    {
        cin>>n>>k;
        for(int i=1;i<=n;i++)
        {
            p[i]=i;
        }
        while(k--)
        {
            int m,x,y;
            cin>>m>>x>>y;
            if(x>n||y>n)
            {
                res++;
            }
            else
            {
                int px=find(x),py=find(y);
                if(m==1)
                {
                   if(px==py&&(d[x]-d[y])%3)res++;
                   else if(px!=py)
                   {
                       p[px]=py;
                       d[px]=d[y]-d[x];
                   }
                }
                else
                {
                    if(px==py&&(d[x]-d[y]-1)%3)res++;
                    else if(px!=py)
                    {
                        p[px]=py;
                        d[px]=d[y]-d[x]+1;
                    }
                }
            }
        }
        cout<<res;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    小点1

    d[px]=d[y]-d[x] 和 d[px]=d[y]-d[x]+1 是怎么来的?
    根据指针指向,m1时,d[x]+?=d[y],?=d[y]-d[x];m2时,d[x]+?-1=d[y],?=d[y]-d[x]+1。

    小点2

    find 函数

    int find(int x)
    {
        if(p[x]!=x)
        {
            int t=find(p[x]);
            d[x]+=d[p[x]];
            p[x]=t;
        }
        return p[x];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这样是对的,大家都能看出来,但有没有人觉得 t 有些多余?
    想改成这样:

    int find(int x)
    {
        if(p[x]!=x)
        {
            d[x]+=d[p[x]];
            p[x]=find(x);
        }
        return p[x];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    但这样是过不了的
    下面的代码却能过:

    int find(int x)
    {
        if(p[x]!=x)
        {
            int t=find(p[x]);
            d[x]+=d[p[x]];
            p[x]=find(p[x]);
        }
        return p[x];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    发现问题所在了吗?
    一般情况下,t 确实无用,但这是递归,p[x] 要不要变,要的,但在什么时候变?
    一定要在先 find(p[x]) 再更新 d[x],为什么?
    因为这是递归,递归什么特点?
    从最后一种情况慢慢往前推,因为你没有办法保证 d[p[x]] 一开始一定存在,所以需要不断地更新 d[x]。

  • 相关阅读:
    pip安装报HTTPSConnectionPool错误解决方案
    idea Debug 模式下tomcat无法启用
    js 正则表达式大全
    Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数
    .NET实现解析字符串表达式
    Java项目:JSP健身房管理系统
    编程参考 - 程序设计中类的生命周期及状态管理
    iOS——引用计数(一)
    Redis_10_Redis集群实现RedisCluster应对大数据量
    计算机毕业设计springboot+vue基本微信小程序的健身教学打开系统app
  • 原文地址:https://blog.csdn.net/m0_64799907/article/details/134098996