thejacoblu

EOJ 3384 食物链

动物王国中有三类动物 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 句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话:

当前的话与前面的某些真的话冲突,就是假话;
当前的话中 X 或 Y 比 N 大,就是假话;
当前的话表示 X 吃 X,就是假话。
你的任务是根据给定的 N (1≤N≤50 000) 和 K 句话 (0≤K≤100 000),输出假话的总数。


 

以下代码来自https://blog.csdn.net/fwq990720/article/details/79108057

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int father[50005], kind[50005];
 5 
 6 int Find(int x)
 7 {
 8     if (x == father[x]) return father[x];
 9     int y = Find(father[x]);
10     kind[x] = (kind[x] + kind[father[x]]) % 3;
11     return father[x] = y;
12 }
13 
14 int Union(int op, int sp1, int sp2)
15 {
16     int x = Find(sp1), y = Find(sp2);
17     if (x == y){
18         if ((kind[sp1] - kind[sp2] + 3) % 3 == op - 1) return 0;
19         return 1;
20     }
21     father[x] = y;
22     kind[x] = (-kind[sp1] + op - 1 + kind[sp2] + 3) % 3;
23     return 0;
24 }
25 
26 int main()
27 {
28     int n, k, op, sp1, sp2, cnt = 0, i;
29     cin >> n >> k;
30     for (i = 1; i <= n; ++i){
31         father[i] = i;
32         kind[i] = 0;
33     }
34     for (i = 0;i < k; ++i){
35         cin >> op >> sp1 >> sp2;
36         if (op == 2 && sp1 == sp2) ++cnt;
37         else if (sp1 > n || sp2 > n) ++cnt;
38         else cnt += Union(op, sp1, sp2);
39     }
40     cout << cnt << endl;
41     return 0;
42 }

 

实在是太难了,找规律实在是难以找到。

经典的种类并查集,需要维护一个kind数组以记录和父节点的关系,并且在查找和合并时,要更新关系。

脑壳疼。

posted @ 2018-03-25 21:04  thejacoblu  阅读(267)  评论(1编辑  收藏  举报