算法
并查集+扩展域
思路
扩展域并查集维护三个域:x_self同类,x_enemy天敌,x_eat捕食。
他们之间的关系:
假设有x,y两个动物,
如果题目给定x和y是同类,那么合并x_self,y_self和x_enemy,y_enemy和x_eat和y_eat。
前提条件是:x_self与y_eat不在同一个集合,x_eat与y_self不在同一个集合。
如果题目给定x吃y,这里我们注意到一点,由于题目给出的食物链关系是环形,因此我们可以由“x吃y”推断出“x的天敌是y的猎物”。
由此得到,合并x_eat,y_self和x_self,y_enemy和x_enemy,y_eat。
前提条件是:x_self和y_self不在一个集合,x_self和y_eat不在一个集合。
代码
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 50006;
int fa[3*N];
int get(int x) {
if (x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
int main() {
int n, k, ans = 0;
cin >> n >> k;
for (int i = 1; i <= 3 * n; i++) fa[i] = i;
while (k--) {
int num, x, y;
scanf("%d %d %d", &num, &x, &y);
if (x > n || y > n || (num == 2 && x == y)) {
++ans;
continue;
}
if (num == 1 && (get(x) == get(y + n) || get(x + n) == get(y))) {
++ans;
continue;
}
if (num == 2 && (get(x) == get(y) || get(x) == get(y + n))) {
++ans;
continue;
}
if (num == 1) {
fa[get(x)] = get(y);
fa[get(x+n)] = get(y + n);
fa[get(x+2*n)] = get(y + 2 * n);
} else {
fa[get(x+n)] = get(y);
fa[get(x+2*n)] = get(y + n);
fa[get(x)] = get(y + 2 * n);
}
}
cout << ans << endl;
return 0;
}