注释版
//当动物x和动物y的距离%3等于1时,说明x捕食y
//当动物x和动物y的距离%3等于2时,说明y捕食x 也可以说y是x的天敌
//当动物x和动物y的距离%3等于0时,说明x和y是同类
#include<iostream>
using namespace std;
const int N=5e4+10;
int animal[N],len[N];//length[x]是x到根节点的距离
int quantity;//假话的数量
int find(int x)//路径压缩
{
if(animal[x]!=x)
{
int u=find(animal[x]);
len[x]+=len[animal[x]];
animal[x]=u;
}
return animal[x];
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) animal[i]=i;
while(m--)
{
int op,x,y;
cin>>op>>x>>y;
if( x>n || y>n ) quantity++;
else
{
int px = find(x), py = find(y);
if(op==1)//真话 x和y是同类
{
if(find(x)==find(y) && (len[x]-len[y])%3)
quantity++;
else if(px!=py)
{
//合并x和y所在集合
animal[px]=py;
/*因为合并x和y所在集合多出了一段长度
这块长度是find(x)到find(y)的距离
所以求多出来的这块部分的长度
当x和y是同类时,有这样的特性
(len[x]+len[find[x]]-len[y])%3==0
这里的len[x]是还未合并时,x到find[x]的距离
∴len[find[x]]=len[y]-len[x]
*/
len[px]=len[y]-len[x];
}
}
else//真话 x捕食y
{
/*
当x和y在一个集合中时,由题目可知,x捕食y
此时有
x到根节点的距离-y到根节点的距离=1+3k k为任意
实数
∴当(len[x]-len[y]-1-3k)%3 ==0 时可确认
x捕食y
反之当(len[x]-len[y]-1-3k)%3 !=0
x不可能捕食y
*/
if(px==py && (len[x]-len[y]- 1) %3)
quantity++;
else if(px!=py)
{
//当x和y不在一个集合时,将x和y所在集合合并
animal[px]=py;
/*
设find(x)到find(y)的距离为len([find(x)])
此时有len[x]+len([find(x)])-len[y]=3k+1
∴len[find(x)]=-len[x]+len[y]+1+3k
*/
len[px]=len[y]+1-len[x];
}
}
}
}
cout<<quantity;
return 0;
}
无注释版
#include<iostream>
using namespace std;
const int N=5e4+10;
int p[N],_l[N],res;
int find(int x)
{
if(p[x]!=x)
{
int u=find(p[x]);
_l[x]+=_l[p[x]];
p[x]=u;
}
return p[x];
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) p[i]=i;
while(m--)
{
int D,X,Y;
cin>>D>>X>>Y;
if(X>n || Y>n) res++;
else
{
int px=find(X),py=find(Y);
if (D==1)
{
if(px==py && (_l[X]-_l[Y])%3) res++;
else if(px!=py)
{
p[px]=py;
//(_l[X]+?-_l[Y])%3=0 so ?=_l[Y]-_l[X]
_l[px]=_l[Y]-_l[X];
}
}
else {
if(px==py && (_l[X]-_l[Y]-1)%3) res++;
else if(px!=py)
{
p[px]=py;
//(_l[X)+?-1-_l[Y])%3=0 so ?=_l[Y]+1-_l[X]
_l[px]=_l[Y]+1-_l[X];
}
}
}
}
cout<<res;
return 0;
}
看到这个+3k我才彻底理解这道题。。。
%%%%
%%%%%%%%%%%%%
大佬给你点赞,总算是有能看懂的代码了,注释写的真厉害,等式推得很棒