蒟蒻太菜了…大佬又要嘲讽我了
用处
对于普通的并查集,我们只维护了每个元素之间的同类关系,但是如果给的关系不一定是同类,可能是像团伙里一样对立的关系,像食物链一样的 A → B , B → C , C → A A\to B,B\to C,C\to A A→B,B→C,C→A的关系,这时候就要用到种族并查集。
实现
种族并查集,就是把同一个集合中的每个元素赋予多个不同的属性,在不同属性的对应元素间建立关系,关系与关系之间能够虽然有冗余,但是互相联系能够很快得出两个元素之间的关系
太懒不想画图了,这是很形象的题解
经典题目
#include <cstdio>
#define N 50005
using namespace std;
int ans, fa[N * 3];
inline int gfa(int x) {
if (fa[x] == x) return x;
fa[x] = gfa(fa[x]);
return fa[x];
}
inline bool check(int a, int b) {
int f1 = gfa(a), f2 = gfa(b);
if (f1 == f2) return 1;
return 0;
}
inline void unite(int a, int b) {
int f1 = gfa(a), f2 = gfa(b);
if (f1 == f2) return;
if (f1 < f2) fa[f2] = f1;
else fa[f1] = f2;
}
int main() {
int n, k, x, a, b;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n * 3; ++i) {
fa[i] = i;
}
while (k--) {
scanf("%d%d%d", &x, &a, &b);
if (a > n || b > n) {
ans++;
continue;
}
if (a == b) {
if (x == 2) ans++;
continue;
}
if (x == 1) {
if (check(a, b + n) || check(a + n, b)) {
ans++;
continue;
}
unite(a, b);
unite(a + n, b + n);
unite(a + (n << 1), b + (n << 1));
}
if (x == 2) {
if (check(a, b) || check(a + n, b)) {
ans++;
continue;
}
unite(a, b + n);
unite(a + n, b + (n << 1));
unite(a +(n << 1), b);
}
}
printf("%d\n", ans);
return 0;
}