【经典种类并查集】食物链

食物链
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 53223   Accepted: 15587

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

解法:
  刚刚学了种类并查集,拿过来试试题,果然关于用并查集分类的话,无论是两类还是N多类都可以用种类并查集来实现的,主要还是要写好判断条件即可,同一个集合表示同一种类。
  题目有三中分类,X,Y,Z,所以我们开一个区间为1~N,对于这个区间中的i,我们规定,i吃(i+N),(i+N)吃(i+2N),(i+2N)吃i。然后对输入的a和b进行判断,分类链接即可。
  比如,输入1 a b的话,要先去判断(a和b+N),(a和b+2N)是否为同一类,如果为同一类的话,则说明a和b不可能为同一类了的。还有就是不能去直接判断(a和b)是否已经不是同一类的,因为你本来就还没连接,如果前面那条件都不符合的话,才去连接(a和b),(a+N和b+N),(a+2N和b+2N),他们为同一类,囧。。。。
  对于输入2 a b的话,表示的是a吃b,所以,我们先去判断a和b是否为同一类,a和b+N是否同一类,如果是的话,则可以判断a吃b这关系是错误的。如果都不是,则说明(a+N和b),(a+2N和b+N),
(a和b+2N)为同一类,连接他们即可。
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <algorithm>
 4 #include <math.h>
 5 #define MAX 2000100
 6 using namespace std;
 7 int ID[MAX];
 8 void Cread(int N)
 9 {
10     for(int i=1;i<=N;i++)ID[i]=i;
11 }
12 int Find(int x)
13 {
14     if(ID[x]!=x)ID[x]=Find(ID[x]);
15     return ID[x];
16 }
17 void Add_(int a,int b)
18 {
19     int A=Find(a);
20     int B=Find(b);
21     if(A!=B)ID[A]=B;
22 }
23 int main()
24 {
25     int N,M,a,b,c,Sign,t=1;
26     scanf("%d%d",&N,&M);
27     {
28         Cread(3*N);Sign=0;
29         while(M--)
30         {
31 
32             scanf("%d%d%d",&c,&b,&a);
33             if(a<=0||a>N||b<=0||b>N){Sign++;continue;}
34             if(c==1)
35             {
36                 if(Find(a)==Find(b+N)||Find(a)==Find(b+2*N))Sign++;
37                 else
38                 {
39                     Add_(a,b);
40                     Add_(a+N,b+N);
41                     Add_(a+2*N,b+2*N);
42                 }
43             }
44             else
45             {
46                 if(Find(a)==Find(b)||Find(a)==Find(b+N))Sign++;
47                 else
48                 {
49                     Add_(a+N,b);
50                     Add_(a,b+2*N);
51                     Add_(a+2*N,b+N);
52                 }
53             }
54         }
55         printf("%d\n",Sign);
56     }
57     return 0;
58 }
View Code

 

posted @ 2015-08-08 15:13  Wurq  阅读(293)  评论(0编辑  收藏  举报