• NOI 2001 & luogu P2024 & POJ 1182食物链


    食物链

    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 71707   Accepted: 21240

    Description

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
    现有N个动物,以1-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(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。

    Input

    第一行是两个整数N和K,以一个空格分隔。
    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
    若D=1,则表示X和Y是同类。
    若D=2,则表示X吃Y。

    Output

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

    Sample Input

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

    Sample Output

    3

    Source

     
     

     

    Solution

    这个并查集是怎么回事?

    我们把已经标记了关系的节点放在一个集合,也就是一棵树

    我们声明rel[i](也就是我也不懂的“偏移量”),

    其实你可以理解 I 到他爸爸的距离(爸爸到i这段链子的长度)qwq

    那,距离怎么可能只有0,1,2呢?因为我将它mod 3啦

    那……为什么要mod 3

    那样我们就可以确定 i 和他爸爸的关系啦

    //P.S. 是不是有点似曾相识?好吧其实我想说google一年级数学题是一件很艰难的事情——

    没错就是这尿性的东西。。。红吃黄,黄吃蓝,蓝又吃红 qwq——这大概就懂了把

    下面是神奇的接链子,还有取模性质的运用

    维护关系

    读入2 x y表示x吃y时,我们需要合并x,y所在的两个集合就是两棵树

    也就是把两条链子接起来

    然后我找x,y爸爸时,在路径压缩时,顺便更新rel的值,

    然后把x的爸爸指向y的爸爸,也要更新rel的值

    判断真假话

    根据2和3判断假话很简单,那根据1呢?

    可以发现我们读入操作-1得到就是我们定义的rel的关系

    于是

    如果查询得出的结果与操作不同就是假话

    否则按照操作合并集合,维护关系即可

     例如:

    当爸爸一样时,表示这两点之间存在关系,

    (b到爸爸距离rel[b]-a到爸爸距离rel[a])%3可以得到a和b的关系  //可以看着上面一年级数学题的图脑补

    //+3是为了防止出现小-大得到负数

    为啥可以mod3值不会出错因为取模运算性质啊!

    Codes

     1 program foodchain;
     2 var
     3    n,k,i,x,a,b,ans:longint;
     4    uset,rel:array[0..50000] of longint;
     5 
     6 function find(app:longint):longint;
     7 var
     8   t:longint;
     9 begin
    10   if uset[app]=0 then exit(app);
    11   t:=find(uset[app]);
    12   rel[app]:=(rel[app]+rel[uset[app]]) mod 3; //因为原本app->uset[app]为rel[app] ,uset[app]->新的root为rel[uset[app]],于是
    13   uset[app]:=t;
    14   find:=uset[app];
    15 end;
    16 
    17 function union(a,b:longint):boolean;
    18 var
    19   p1,p2:longint;
    20 
    21 begin
    22   p1:=find(a);
    23   p2:=find(b);
    24   if p1=p2 then             //之前已经存在关系
    25     if (rel[b]-rel[a]+3) mod 3<>x-1 then exit(false)
    26       else exit(true);
    27 
    28   uset[p2]:=p1;
    29   rel[p2]:=(rel[a]+3-rel[b]+x-1) mod 3;
    30   exit(true);
    31 end;
    32 
    33 begin
    34     readln(n,k);
    35 
    36     for i:= 1 to k do
    37       begin
    38           readln(x,a,b);
    39           if (a>n) or (b>n) or ((x=2) and (a=b)) then inc(ans)
    40            else  if union(a,b)=false then inc(ans);
    41       end;
    42 
    43     writeln(ans);
    44 end.
  • 相关阅读:
    homebrew
    Flutter状态管理之provide和provider的使用区别
    Flutter Bloc状态管理 简单上手
    Flutter 路由传入中文参数报错无法push问题
    Flutter 一些常用第三方库、插件
    js替换字符串中的空格,换行符 或 替换成<br>
    Flutter状态管理Provider,简单上手
    Flutter Resolving dependencies...很慢解决办法
    Flutter布局--appbar导航栏和状态栏
    Flutter运行报错 `kernel_snapshot for errors` 解决方案
  • 原文地址:https://www.cnblogs.com/bobble/p/6891708.html
Copyright © 2020-2023  润新知