【并查集】【种类并查集】食物链
https://ac.nowcoder.com/acm/contest/22904/1024
参考
https://www.luogu.com.cn/problem/solution/P2024
这是一个典型的并查集问题,可以通过“带有偏移的并查集”来解决。由于题目涉及食物链的关系,可以将“同类”与“吃”的关系进行合并操作和冲突检测。
这里我们使用一种特殊的并查集,即带有偏移的并查集来处理这个问题,将每个动物的状态分为3类状态。
以下是解题思路和代码示例:
思路
定义并查集:每个动物有3种状态(自己、吃它的和被它吃的),将每个动物的3种状态分别表示为 i、i+N、i+2N。
i 表示第 i 个动物的 "A 类"
i+N 表示第 i 个动物的 "B 类"
i+2N 表示第 i 个动物的 "C 类"
合并关系:
如果两个动物是同类(D=1),那么它们的三种状态需要分别相等。
如果 X 吃 Y(D=2),则 X 的状态应该在 Y 的前一个状态上。
判断假话:
如果 X 或 Y 超出 N,或者 X 吃 X,则必定是假话。
如果当前的话与之前建立的关系产生冲突,则是假话。
// 并查集模板省略
int main() {
int N, K;
cin >> N >> K;
UnionFind uf(3 * N + 1);
int falseCount = 0;
while (K--) {
int D, X, Y;
cin >> D >> X >> Y;
if (X > N || Y > N || (D == 2 && X == Y)) {
falseCount++;
continue;
}
if (D == 1) {
if (uf.isConnected(X, Y + N) || uf.isConnected(X, Y + 2 * N)) {
falseCount++;
} else {
uf.unite(X, Y);
uf.unite(X + N, Y + N);
uf.unite(X + 2 * N, Y + 2 * N);
}
} else if (D == 2) {
if (uf.isConnected(X, Y) || uf.isConnected(X, Y + 2 * N)) {
falseCount++;
} else {
uf.unite(X, Y + N);
uf.unite(X + N, Y + 2 * N);
uf.unite(X + 2 * N, Y);
}
}
}
cout << falseCount << endl;
return 0;
}