一、题目描述
食物链
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 109981 Accepted: 33398
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
Source
Noi 01
二、算法分析说明与代码编写指导
并查集的每个集合都具有一种或多种相同的特性。利用这个特点,可以将同种生物合并到一起,并按照捕食关系将被捕食者的根节点设为捕食者。
已知A吃B,B吃C,C吃A。若x与y为同种生物,x和y可能同为A或B或C物种。
若x吃y,x和y的物种分别可以是A和B、B和C、C和A。可见,这三种情况我们都需要考虑,所以我们设数组r,用到的长度为n的三倍,有效的下标从1开始。x、x+n、x+2n分别代表x属于物种A、x属于物种B、x属于物种C三种情况。每处理一句真话,都要针对这三种情况对并查集进行修改。
本题的并查集启用了压缩路径,无论是查找还是合并都尽可能地减少了并查集的层数。
对任意两个编号分别为x,y的生物,如果它们的根相同,那么它们属于同一个物种。如果它们属于三个离散闭区间[1, n], [n+1, 2n], [2n+1, 3n]中不同的区间,则它们是不同物种。
处理K句话。如果x>n或y>n,代表描述的动物不在1~n编号的范围,按题目要求,将假话数量+1。
否则,根据描述的种类来进行处理。
对第一类描述,如果求根发现两者存在吃或被吃的关系(查找只需要找一种情况,即A吃B、B吃C、C吃A中的一种,但注意x吃y和y吃x都要验证是否成立),那么这句话与已有条件冲突,为假话。否则,将x与y的根合并(x和y为A、B、C物种三种情况都要处理)。
对第二类描述,如果求根发现两者为同一物种(同为A或B或C),或捕食关系与当前描述相反,则这句话与已有条件冲突,为假话。
否则,按照x与y可以分别属于A和B、B和C、C和A物种三种情况来合并并查集的根节点。
Extra:
本例中,虽然对并查集的两个基本操作——查询和合并,都已经作了压缩路径的处理,但并不是所有时候都能确保每个并查集的层次只有2层。有时候,当某个并查集的根节点被修改为指向另一个并查集的根时,这个根节点连接的子节点的根节点仍然指向这个根节点本身,还未被处理。
例如当输入为: