食物链:
网上看的别人的加过注释的代码,对于rank的解释很好,就摘录了
#include<iostream>
using namespace std;
const int Max = 50005;
int n, pa[Max], rank[Max];
void make_set(){
for(int x = 1; x <= n; x ++){
pa[x] = x;
rank[x] = 0; // 开始时集合的根也是x,属于同种类型,故类型差值为0。
}
}
int find_set(int x){
int tmp = pa[x];
if(x != pa[x]){
pa[x] = find_set(pa[x]);
rank[x] = (rank[x] + rank[tmp]) % 3;
//rank[x]是x相对原来的根元素tmp(前根节点)的差值,现在的根元素已不是tmp。
//故要加上tmp对于现在的根元素的类型差值,rank[tmp]为tmp对于现在根元素类型的差值。
}
return pa[x];
}
void union_set(int x, int y, int w){
int a = find_set(x);
int b = find_set(y);
pa[b] = a;
rank[b] = (rank[x] - rank[y] + w + 3) % 3;
//这个公式可用列表推出,列表时必须保证rank[x]不变,由于根节点的rank[a]总为0。
//然后如果x吃y,则rank[y] = rank[x] + 1,然后可推出rank[b]的改变量。x与y同类也运用这个思路。
}
int main(){
int t, ans = 0;
scanf("%d %d", &n, &t);
make_set();
while(t --){
int d, x, y;
scanf("%d %d %d", &d, &x, &y);
if(x > n || y > n) ans ++; // 当前的话中X或Y比N大,就是假话。
else{
if(d == 1){
if(find_set(x) == find_set(y) && rank[x] != rank[y]) ans ++;
else union_set(x, y, 0);
}
if(d == 2){
if(find_set(x) == find_set(y) && (rank[x]+1) % 3 != rank[y]) ans ++;
else union_set(x, y, 1);
}
}
}
printf("%d\n", ans);
return 0;
}