解题思路
已知A吃B,B吃C,C吃A。
所有有关系的动物在一个并查集里,但是这个并查集不简单,它是一个带权的并查集!
那么这个权值是什么呢?
设A与B在同一个集里,A到根节点X的权值(模3)为
Da
,B到根节点权值(模3)为
Db
如果
Da=2
,则X吃A。
如果
Da=1
,则A吃X。
如果
Da=0
,则A与X为同一物种。
由此可以得到:
如果
Da=Db+1(mod3)
,则A吃B
如果
Da=Db−1(mod3)
,则B吃A
如果
Da=Db(mod3)
,则A与B同类
那么路径压缩就可以解决此问题了(具体看代码)!
如果x和y不在同一个集里,那么就合并,否则查询是否满足条件。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<climits>
using namespace std;
const int N=50005;
int n,m,ans;
int f[N],d[N];
int find(int x){
if(f[x]==x)return x;
int kl=f[x];
f[x]=find(f[x]),d[x]=(d[x]+d[kl]+3)%3;//路径压缩d
return f[x];
}
int main()
{
int i,j,x,y,bj,r1,r2;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)f[i]=i;
for(i=1;i<=m;++i){
scanf("%d%d%d",&bj,&x,&y);
if(x>n||y>n){++ans;continue;}
if(bj==2&&x==y){++ans;continue;}
r1=find(x),r2=find(y);
if(r1!=r2){
f[r1]=r2;
if(bj==2)d[r1]=(d[y]-d[x]+4)%3;//给新边d赋值
else d[r1]=(d[y]-d[x]+3)%3;
}
else {
if(bj==1&&d[x]%3!=d[y]%3)++ans;//检查是否相等
else if(bj==2&&d[x]%3!=(d[y]+1)%3)++ans;
}
}
printf("%d",ans);
return 0;
}