【并查集】【种类并查集】食物链

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;
}
posted @ 2024-10-27 00:58  peterzh6  阅读(4)  评论(0编辑  收藏  举报