食物链
首先可知 A 吃 B,B 吃 C,C 吃 A。故知道A和B,B和C的关系,便可推出A和C的关系。
主要思想
维护一个集合,若两动物已经在集合中,便可判断其关系是否正确,若不在集合中,便可加入集合。那么怎么判断当前加入的动物是A,B,C中的哪类动物呢?可以用一个距离数组记录(假设为d),那么d[i]为动物i到根节点的距离,将其%3即d[i]%3即可判断他是哪类动物(假设1吃0,2吃1,0吃2)并且不断维护这个数组即可。
那么并查集find的模板代码为
int find(int x) //p[x]为并查集,d[x]为距离
{
if(p[x]!=x)
{
int t=find(p[x]); //首先记录下p[x]的祖先
d[x]+=d[p[x]]; //更新距离
p[x]=t;
}
return p[x];
}
主要代码
while(k--)
{
int m,x,y;
scanf("%d%d%d",&m,&x,&y);
if(x>n||y>n)
{
res++;
continue;
}
int px=find(x),py=find(y);
if(m==1)
{
if(px==py&&(d[x]-d[y])%3) res++; //当已经在集合当中,并且为同类时
如果(d[x]-d[y])%3!=0那么假话数加一
else if(px!=py)
{
p[px]=py;
d[px]=d[y]-d[x]; //祖先的距离计算如下图,不需要改变d[x],因为在find函数中
} 会动态维护d[x]的值。
}
else
{
if(px==py&&(d[x]-d[y]-1)%3) res++;
else if(px!=py)
{
p[px]=py;
d[px]=d[y]-d[x]+1; //同理
}
}
}
全部代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=50010;
int p[N];
int d[N];
int n,k;
int find(int x)
{
if(p[x]!=x)
{
int t=find(p[x]);
d[x]+=d[p[x]];
p[x]=t;
}
return p[x];
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++) p[i]=i;
int res=0;
while(k--)
{
int m,x,y;
scanf("%d%d%d",&m,&x,&y);
if(x>n||y>n)
{
res++;
continue;
}
int px=find(x),py=find(y);
if(m==1)
{
if(px==py&&(d[x]-d[y])%3) res++;
else if(px!=py)
{
p[px]=py;
d[px]=d[y]-d[x];
}
}
else
{
if(px==py&&(d[x]-d[y]-1)%3) res++;
else if(px!=py)
{
p[px]=py;
d[px]=d[y]-d[x]+1;
}
}
}
cout<<res<<endl;
}