PKU1182:食物链

食物链
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 17712 Accepted: 4953

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 71 101 1 2 1 22 2 3 2 3 3 1 1 3 2 3 1 1 5 5

Sample Output

3

____________________________________________________________________________________________________________________________

题解

一看题,发现是并查集。但是想了半天没有什么想法,因为无法判断该动物到底是A,B还是C,无法确定并查集的数量。

看了DISCUSS,发现利用相对关系真的非常精妙。

只需要一个并查集,每个节点记录与父亲(注意是父亲,不是祖先)的关系:0同类,1食物,2天敌。通过它与父亲的关系,及父亲与父亲的父亲的关系可以确定它与父亲的父亲的关系,进而可以求出它与祖先的关系。那么对于新加入的两个数,先判断他们是否在并查集里,不在的话直接添加。如果两个数已经在并查集里,那么分别求出他们与祖先的关系(他们的祖先是同一个,因为只有一个并查集),通过他们与祖先的关系就可以知道他们两的关系,然后与输入比对就可以知道是不是假话。

 

代码:

 

代码
1 //父亲是儿子的天敌,食物,同类。0同类,1食物,2天敌。 路径压缩,否则超时。
2  #include<stdio.h>
3  int father[50002],ship[50002];
4  int fb,fc,sb,sc,b,c,a,i,n,k,sum;
5  int getancestor(int x)
6 {
7 int temp;
8 temp=x;
9 while (father[temp]!=temp)
10 temp=father[temp];
11 return temp;
12 }
13 int getship(int x)
14 {
15 int relation,temp;
16 temp=x;
17 relation=0;
18 while (father[temp]!=temp)
19 {
20 relation=(relation+ship[temp])%3;
21 temp=father[temp];
22 }
23 father[x]=temp;
24 ship[x]=relation;
25 return relation;
26 }
27 int main()
28 {
29 scanf("%d%d",&n,&k);
30 for (i=1;i<=n;i++)
31 {
32 ship[i]=0;
33 father[i]=i;
34 }
35 sum=0;
36 for (i=1;i<=k;i++)
37 {
38 scanf("%d%d%d",&a,&b,&c);
39 fb=getancestor(b);
40 fc=getancestor(c);
41 if (b>n||c>n||(a==2&&b==c))
42 {
43 sum++;
44 continue;
45 }
46 sc=getship(c);
47 sb=getship(b);
48 if (a==1)
49 {
50 if (fc!=fb)
51 {
52 father[fc]=b;
53 ship[fc]=(3-sc)%3;
54 }
55 else
56 if (sb!=sc) sum++;
57 }
58 else
59 {
60 if (fc!=fb)
61 {
62 father[fc]=b;
63 ship[fc]=(2-sc)%3;
64 }
65 else
66 if (sb!=(sc+1)%3) sum++;
67 }
68 }
69 printf("%d\n",sum);
70 return 0;
71 }
72
73
74

 

posted on 2010-07-28 12:46  风也轻云也淡  阅读(400)  评论(0编辑  收藏  举报