【並查集】【帶偏移的並查集】食物鏈

peterzh6發表於2024-10-27

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;
}

相關文章