题目链接:https://ac.nowcoder.com/acm/problem/16884
刚看到这道题的时候听懵逼的,只能看出来是并查集,但觉得要加上权值做法很复杂 ,后来听毛毛雨姐姐讲完课以后顿悟了,只要将n的数量级开三倍,来表示三个层次就能解决问题,简化了不少。
思路:
将数组开3倍大,a表示自身的一层(即a类),a+n表示被a吃掉的一类,a+2n表示能吃a的一类。
判断一个语句是否为真,则只要判断它的反例是否成立。如 1 A B,表示A 和B 是一类的 那么只要判断A和B+n或者A和b+2
n是不是一类的 如果是,说明这句话是假话,否则就是真话。
并查集的基本操作merge(归并) 和find 就不多说了。
具体细节看代码以及代码中的注释吧:

#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define ll long long
using namespace std;
#define close_stdin  ios::sync_with_stdio(false)
const int maxn = 50000;
int n, k;
int d, x, y,ans=0;
int fa[3 * maxn + 50];
int find(int x) {
    return (x == fa[x] ? x : fa[x]=find(fa[x]));
}
void my_merge(int x,int y){  // 将两种动物归并到一类中
    fa[find(x)] = find(y);

}
void my_input() {            //初始化 fa数组 使得每个人一开始为孤立的 以便后续建立关系
    cin >> n >> k;
    for (int i = 1;i <= 3 * n;i++) { fa[i] = i; }
}
void solve() {
    for (int i = 1;i <= k;i++) {
        cin >> d >> x >> y;
        if (x > n || y > n) { ans++;continue; }
        else if (d == 1) {
            if (find(x) == find(y + n) || find(x) == find(y + 2 * n)) { ans++;continue; } //x和y是同类  所以x和y必须在同层 否则就是假话
            my_merge(x, y);
            my_merge(x + n, y + n);
            my_merge(x + 2 * n, y + 2 * n);
        }
        else {
            if (find(x) == find(y) || find(x) == find(y + 2 * n)) { ans++;continue; }  // x吃y 所以 x在第一层 y在第二层 或者 x在第二层 y在第三层 或者x在第三城 y在第一层 否则是假话
            my_merge(x, y + n);
            my_merge(x+n, y +2* n);
            my_merge(x+2*n, y );
        }
    }
    cout << ans << "\n";
}
int main() {
    close_stdin;
    my_input();
    solve();
}