zoukankan      html  css  js  c++  java
  • $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'
  • 相关阅读:
    .NET Remoting 应用实例
    EXT.NET 使用总结(3)--动态图表
    2013,2014
    TreeMap put 操作分析
    C#排序算法小结
    高性能的JavaScript--数据访问(1)
    javascript生成对象的三种方法
    Android开发中经常使用的Content-Type简介
    git diff提示filemode发生改变(old mode 100644、new mode 10075)
    UIWebView的使用
  • 原文地址:https://www.cnblogs.com/Peter0701/p/11815459.html
Copyright © 2011-2022 走看看