建议列一个关系图

列出题目所给的关系图,对于一个物种x,有

alt

那么为了列出这三种关系,我们需要将域扩大到原来的三倍(n*3),定义x类,则x+n是它捕食的一类,x+2n是捕食它的一类

那么d == 1时,x与y+n,y+2n在同一层的话为矛盾

对于d == 2,我们将关系图补全

alt

我们可以清晰看到x与y,yy不是同一类,如果出现这样的关系即为矛盾。 归并时按照图中关系归并即可。

下面是代码

/* NC16884 食物链 */
/* 2024.3.17 扩展域并查集*/
//开三倍的n,表示同类,被x吃的类,能吃x的类
#include<bits/stdc++.h>
using namespace std;
const int N = 5e4 + 10;
int n, k;
int fa[N*3];

int find(int x){
    return fa[x] == x ? x : find(fa[x]);
}

int main(){
    ios::sync_with_stdio(0);
    cin >> n >> k;
    for (int i = 1; i <= n*3; i++){
        fa[i] = i;
    }
    int res = 0;
    while(k--){
        int t, x, y;
        cin >> t >> x >> y;
        if(x > n || y > n){
            res++;
            continue;
        }
        int f1 = find(x);
        int f2 = find(y);
        int ff1 = find(x+n);
        int ff2 = find(y+n);
        int fff1 = find(x+n+n);
        int fff2 = find(y+n+n);
        if(t == 1){
            if(f1 == ff2 || f1 == fff2){ //同类必须在同层
                res++;
                continue;
            }
            fa[f1] = f2;
            fa[ff1] = ff2;
            fa[fff1] = fff2;
        }
        else if(t == 2){ //x吃y关系,y被吃层中x,x能吃层中y
            if(x == y || f1 == f2 || f1 == ff2) {//同城,关系倒转为错
                res++;
                continue;
            }
            //这是一个环形的食物链
            fa[f1] = fff2;
            fa[ff1] = f2;
            fa[fff1] = ff2;
        }
    }
    cout << res << "\n";
    return 0;
}