解题思路:将并查集分为三个部分 分别是同类,猎物 ,天敌,取x(x属于1~n)举个栗子,与x一块的为x的同类,与x+n为一块的为x的猎物,与x+2*n为一块的为x的天敌。我们只需要同时维护这三个部分,并用来判断假话即可。由于只有A,B,C三种动物,那么A猎物的猎物就是A的天敌这需要注意维护。代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int maxn=5e4+5;
int fa[maxn*3],rk[maxn*3]; //一部分代表同类, 二猎物 ,三天敌
int n,k,ans=0;
void init(){
for(int i=0;i<maxn*3;++i)
fa[i]=i,rk[i]=1;
}
int find(int x){
if(x==fa[x]) return fa[x];
else return fa[x]=find(fa[x]);
}
bool ck(int x,int y){
x=find(x),y=find(y);
if(x==y) return true;
else return false;
}
void unite(int x,int y){
x=find(x),y=find(y);
if(rk[x]<rk[y]) fa[x]=y;
else{
if(rk[x]==rk[y]) rk[x]++;
fa[y]=x;
}
}
int main(){
std::ios::sync_with_stdio(0);
init();
cin>>n>>k;
int x,y,z;
for(int i=1;i<=k;++i){
cin>>z>>x>>y;
if(x>n || y>n){
ans++;
continue;
}
if(z==1){ //同类
if(find(x+n)==find(y) || find(x+2*n)==find(y) ){
//y是x的猎物 或者 y是x的天敌 即为假话
ans++;
continue;
}
unite(x,y),unite(x+n,y+n),unite(x+2*n,y+2*n);
//x的同类也是y的同类合并,猎物和天敌同理
}
else if(z==2){ //x吃y
if(find(x)==find(y) || find(x)==find(y+n)){
//x与y是同类 或者 y的猎物有x
ans++;
continue;
}
unite(x+n,y),unite(x,y+2*n),unite(x+2*n,y+n);
//x的猎物与y是同类 x的同类是y的天敌 x的天敌是y的猎物
}
}
cout<<ans<<endl;
return 0;
}