POJ 1182 食物链
食物链
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 34498 | Accepted: 10026 |
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对c的关系为:a.relation,b对c的关系为b.relation,那么a对b的关系为(a.relation-b.relation+3)%3
加3是为了防止前面的做差变成负数,导致取模后符号出现问题
由此公式可以推到出Find(),Merge()函数中的几个关系式
Find()中还用到了一个技巧就是要记录他的前任父亲:
由于在两个集合合并时只能调整祖先的关系,而无法调整叶子节点的关系,所以在Find()函数中每次要记录该叶子节点的前任父亲,然后根据更新后的前任父亲状态更新自身的状态
代码如下,用了Codeblocks,代码整洁多了^_^
1 #include<stdio.h> 2 3 typedef struct sth 4 { 5 int relation; 6 long father; 7 } NODE; 8 9 long n, k; 10 NODE animal[50001]; 11 12 void MakeSet() 13 { 14 int i; 15 16 for (i = 1; i <= n; i++) 17 { 18 animal[i].relation = 0; 19 animal[i].father = i; 20 } 21 } 22 23 void Merge (long a, long b, long x, long y, int d) 24 { 25 animal[a].father = b; 26 animal[a].relation = (animal[y].relation - animal[x].relation + 2 + d) % 3; 27 } 28 29 long Find (long x) 30 { 31 long pre_father; 32 33 if (x != animal[x].father) 34 { 35 pre_father = animal[x].father; 36 animal[x].father = Find (animal[x].father); 37 animal[x].relation = (animal[x].relation + animal[pre_father].relation) % 3; 38 } 39 40 return animal[x].father; 41 } 42 43 int main() 44 { 45 int d; 46 long a, b, x, y, sum = 0; 47 48 scanf ("%ld %ld", &n, &k); 49 50 MakeSet(); 51 52 while (k--) 53 { 54 scanf ("%d %ld %ld", &d, &x, &y); 55 if ( (x > n) || (y > n) || ( (x == y) && (d == 2))) 56 sum++; 57 else 58 { 59 a = Find (x); 60 b = Find (y); 61 if ( (a == b) && ( (animal[x].relation - animal[y].relation + 3) % 3 != d - 1)) 62 sum++; 63 else if (a != b) 64 Merge (a, b, x, y, d); 65 } 66 } 67 printf ("%ld\n", sum); 68 return 0; 69 }