POJ 1182 食物链 (关系并查集)

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


思路:根据题意想A,B,C构成mod3的关系,如果D=2表示x吃y,这时会出问题:x吃y,y吃z,那么x到z的关系为4%3=1,于是x到z的关系为x与y是同类;
但是z到x的关系为3-1=2,即z吃x,于是出现矛盾。
所以我们应该使0表示同类,1,2分别表示吃与被吃的关系。这样才能推通。 如果之前的话中x与y的关
系还不能被推出,那么合并x与y,并算出x与y的关系;如果之前的话中已知x与y的关系,那么判断当前x
与y的关系是否与之前说过的话有冲突,如果有,那
么谎话++,否则不做操作;题目中给的d=2时,x吃x的情况其实可以看做是同一集合当前谎话与之前说过的话的冲突来处理


 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 int const N=50010;
 7 int f[N];
 8 int rela[N];
 9 
10 int Find(int a)
11 {
12     int r=0;
13     int b=a;
14     while(b!=f[b])
15     {
16         r += rela[b];
17         b=f[b];
18     }
19     while(f[a]!=b)
20     {
21         int tmp = f[a];
22         f[a]=b;
23         r -= rela[a];
24         rela[a] += r;
25         a = tmp;
26     }
27     return b;
28 }
29 
30 void Union(int x,int y,int r)
31 {
32     int fx=Find(x);
33     int fy=Find(y);
34     rela[fx]=rela[y]-rela[x]+r;
35     f[fx]=fy;
36 }
37 
38 int main()
39 {
40     int m,n;
41     scanf("%d%d",&m,&n);
42 
43         for(int i=1;i<=m;i++)
44         {
45             f[i]=i;
46             rela[i]=0;
47         }
48         int k=0;
49         while(n--)
50         {
51             int d,x,y;
52             scanf("%d%d%d",&d,&x,&y);
53             if(x>m||y>m) k++;
54             else if(Find(x)==Find(y))
55             {
56                 if(((rela[x]-rela[y])%3+3)%3!=d-1) k++;
57             }
58             else if(Find(x)!=Find(y))
59                 Union(x,y,d-1);
60         }
61         printf("%d\n",k);
62 
63     return 0;
64 }

 

posted @ 2016-08-05 20:16  lianyuAngel  Views(145)  Comments(0)    收藏  举报