//核心思想:并查集维护点到根节点的距离
//由于是环状食物链,所以可构建以下关系
//通过集合里各点到根节点的距离来判断各点间的关系
//1. 点到根节点距离模3为1 该类点吃3.情况的点,被2.情况的点吃
//2. 点到根节点距离模3为2 该类点吃1.情况的点,被3.情况的点吃
//3. 点到根节点距离模3为0 该类点吃2.情况的点,被1.情况的点吃
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5e4+10;
int res = 0;
int p[N],d[N];//d[i]表示i点到根节点的距离
int find(int x) // 并查集维护各点到根节点的距离
{
if (p[x] != x)
{
int u = find(p[x]);//这里需要先存一下根节点
d[x]+=d[p[x]];//让d[x]先加上p[x]到根节点的距离
p[x]=u;//再路径压缩,更新p[x]
}
return p[x];
}
int main()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++) p[i]=i;
for(int i=0;i<k;i++)
{
int a,b,c;
cin>>c>>a>>b;
int pa=find(a),pb=find(b);
if(a>n||b>n)
{
res++;
}
else if(c==1)
{
if(pa==pb&&(d[a]-d[b])%3) res++;//如果二者已在集合内,且不为同类,则为谎话,res++
else if(pa!=pb)//如果二者还未在集合内,则合并集合
{
p[pa]=pb;
//d[pa]需要我们自己构造,使得a,b两点满足同类关系
d[pa]=(d[b]-d[a]);//因为二者为同类,所以到根节点的关系要满足(d[a]+d[pa])%3==d[b]%3
}
}
else if(c==2)
{
if(pa==pb&&(d[a]-d[b]-1)%3) res++;//如果二者已在集合内,且不为a吃b的关系,则为谎话,res++
else if(pa!=pb)//如果二者还未在集合内,则合并集合
{
p[pa]=pb;
//同上,d[pa]需要我们自己构造,使得a,b两点满足a吃b的关系
d[pa]=(d[b]+1-d[a]);//因为二者存在a吃b的关系,所以到根节点的关系要满足(d[a]+d[pa]-1)%3=d[b]%3
}
}
}
cout<<res;
}
Acwing 240. 食物链
最新推荐文章于 2026-01-03 02:32:32 发布
该程序使用并查集数据结构处理环状食物链问题,通过维护点到根节点的距离来判断不同点之间的吃与被吃关系。当接收到新的食物链信息时,检查是否符合模3关系,并进行集合的合并与路径压缩。最后输出不符合规则的谎话数量。
502

被折叠的 条评论
为什么被折叠?



