• $Luogu$ $P2024$ $[NOI2001]$ 食物链


    链接

    背景

    (CCF) (NOI) (2001) (Day1) (T1)(Luogu) (P1955/Vijos1531)

    题意

    给定三种动物 (A,B,C)(n) 只(现在不确定种类)。规定 (A)(B)(B)(C)(C)(A) ,给出 (n) 句话形如 (1 X Y(X,Y in [1,n])) 或者 (2 X Y(X,Y in [1,n])) ,前一种描述 (X)(Y) 是同类。后一种描述 (X)(Y) 。规定一句话是假的的情况有三种:第一是给出的动物编号超过 (n) ,第二是当前这句话与比它早出现的话矛盾,第三是当前的话表示 (X)(X) 。求假话的数量。

    解法

    大名鼎鼎的扩展域并查集(种类并查集)出场啦!
    因为关系只有吃、被吃和同类三种,考虑把每只动物 (x(x in [1,n])) 拆成仨集合 (x_{self},x_{enemy},x_{eat}) ,分别表示自己的同类集合、天敌集合以及食物集合,下标分别对应 ([1,n],[n+1,2n]) 以及 ([2n+1,3n])
    考虑怎么维护这三个集合。对于一句话,可以大力先把动物编号超过 (n) 的判掉,把表示 (X)(X) 的话判掉,于是问题就只有判断这句话与比它早出现的话矛盾了。考虑关系是按话给出的先后顺序维护的,于是只要它与已经形成的集合相违背就是假话。
    然后问题就变成了对于一句真话咋维护集合。首先考虑 (X)(Y) 是同类的情况,则两者的同类集合、天敌集合以及食物集合都是完全相同的,于是把两个元素的六个集合直接合并(即合并 (X_{self})(Y_{self})(X_{enemy})(Y_{enemy})(X_{eat})(Y_{eat}) )即可。然后是 (X)(Y) 的情况,根据题意有 (X)(Y) 时必有 (X)(Y) 的天敌, (Y)(X) 的天敌,于是按题意合并即可(即合并 (X_{self})(Y_{enemy})(X_{enemy})(Y_{eat})(X_{eat})(Y_{self}) )。
    最后再讲下假话的具体判断方法:不满足 (X)(Y) 是同类的情况是 (X)(Y) 或者 (Y)(X) ,问题就转换成了判定 (X)(Y) 或者 (Y)(X) 是否存在,即判断 (X_{self})(Y_{eat}) 是否在同一集合、 (Y_{self})(X_{eat}) 是否在同一集合。不满足 (X)(Y) 情况是 (X)(Y) 是同类或者 (Y)(X) ,问题就转换成了判定 (X)(Y) 是同类或者 (Y)(X) 是否存在,即判断 (X_{self})(Y_{self}) 是否在同一集合、 (Y_{self})(X_{eat}) 是否在同一集合。

    代码

    $View$ $Code$ ```cpp #include using namespace std; inline int read() { int ret=0,f=1; char ch=getchar(); while('9'
  • 相关阅读:
    【[AH2017/HNOI2017]礼物】
    【[ZJOI2014]力】
    FFT抄袭笔记
    【[SCOI2015]小凸玩矩阵】
    【[SDOI2017]新生舞会】
    bzoj 3277: 串
    【[ZJOI2015]诸神眷顾的幻想乡】
    【[TJOI2017]DNA】
    【[TJOI2018]碱基序列】
    【[TJOI2018]异或】
  • 原文地址:https://www.cnblogs.com/Peter0701/p/11815459.html
Copyright © 2020-2023  润新知