描述
动物王国中有三类动物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),输出假话的总数。
输入
第一行是两个整数N和K,以一个空格分隔。
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
输出
只有一个整数,表示假话的数目。
样例输入
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
样例输出
3
代码
//食物链
#include<iostream>
#include<stdio.h>
using namespace std;
struct animal {
int father;
int relation;
}Animals[50010];
int N, K;
int D, X, Y;
int sum = 0;
void init() {
for (int i = 1;i <= N;i++) {
Animals[i].father = i;
Animals[i].relation = 0;
}
}
int findFather(int x) {
if (Animals[x].father != x) {
int father = Animals[x].father;
Animals[x].father = findFather(Animals[x].father);
Animals[x].relation = (Animals[father].relation + Animals[x].relation) % 3;
}
return Animals[x].father;
}
int main() {
cin >> N >> K;
init();
for (int i = 0;i < K;i++) {
scanf("%d %d %d", &D, &X, &Y);
if (X > N || Y > N) {
sum++;
}
else if (X == Y && D == 2) {
sum++;
}
else {
int Xfather = findFather(X);
int Yfather = findFather(Y);
if (Xfather == Yfather) {
if (D == 1) {
if (Animals[X].relation != Animals[Y].relation)
sum++;
}
else if (D == 2) {
if ((Animals[X].relation == 0 && Animals[Y].relation != 1) || (Animals[X].relation == 1 && Animals[Y].relation != 2) || (Animals[X].relation == 2 && Animals[Y].relation != 0))
sum++;
}
}
else {
if (D == 1) {
Animals[Yfather].father = Xfather;
if (Animals[X].relation == Animals[Y].relation) {
Animals[Yfather].relation = 0;
}
else if ((Animals[X].relation+2)%3==Animals[Y].relation) {
Animals[Yfather].relation = 1;
}
else if ((Animals[X].relation+1)%3==Animals[Y].relation) {
Animals[Yfather].relation = 2;
}
}
else {
Animals[Yfather].father = Xfather;
if ((Animals[X].relation + 1) % 3 == Animals[Y].relation) {
Animals[Yfather].relation = 0;
}
else if (Animals[X].relation == Animals[Y].relation) {
Animals[Yfather].relation = 1;
}
else if ((Animals[X].relation + 2) % 3 == Animals[Y].relation) {
Animals[Yfather].relation = 2;
}
}
}
}
}
cout << sum << endl;
return 0;
}
唯一需要注意的点是,并查集的使用并不是把所有属于同种的放到一个集合里,而是通过语句将两个生物放到一个集合里,因此需要计算生物之间的关系。这个并不难计算,枚举所有情况推一下就能算出来。语句会出错的除了编号超过N这种的,还有就是跟前面语句矛盾,这意味着这两个生物已经在一个集合里了,只要语句里的关系跟他们在集合里推算出的关系不一致就是语句出错。