poj1182 食物链 带权并查集

时间:2023-03-09 17:25:22
poj1182  食物链              带权并查集

题目传送门

题目大意:大家都懂。

思路:

  今天给实验室的学弟学妹们讲的带权并查集,本来不想细讲的,但是被学弟学妹们的态度感动了,所以写了一下这个博客,思想在今天白天已经讲过了,所以直接上代码。

首先,带权并查集必备知识是向量加减规则,不熟悉的可以看我的另外一篇博客(点我

  先放图,模拟的是  x吃y  和x和y同类的向量合并。

这应该是最难的地方,很多东西白天已经讲过了,具体看代码,我写了比较详细的注释。

poj1182  食物链              带权并查集

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=;
int p=;
//p%3==0 由于下面有向量相减 可能部分value是负的,所以加上一个比较大的数字变成正数
int fa[maxn],n,k,ans,type,x,y,value[maxn];
//value数组 永远记录的都是 当前节点 到fa[x]的权值 此时fa[x]对应的value不一定更新了 ,需要find进行路径合并
//记住 find的功能是找爸爸 + 路径合并 + 更新value[x]
// baba函数的功能是 联合 向量规则更新value
// x->y的权值是1,就是x吃y
int find(int x)
{
if(x==fa[x])return fa[x];
int tep=fa[x]; //先保存当前的还没有路径合并的父节点
fa[x]=find(fa[x]); //把 父节点权值信息更新
value[x]+=value[tep]; //value存的是x到之前的父节点的信息,现在加上 原父节点(tep)合并路径后的权值
return fa[x];
}
void baba(int x,int y,int type)
{
int fx=find(x),fy=find(y);
if(type==) //平级权值为0
{
fa[fx]=fy;
value[fx]=-value[x]+value[y]+; //x的爸爸认y的爸爸当爸爸,用向量规则进行加减
}else{ //x吃y 权值1
fa[fx]=fy;
value[fx]=-value[x]+value[y]+; //x的爸爸认y的爸爸当爸爸,用向量规则进行加减
}
}
int main(){
cin>>n>>k;
for(int i=;i<=n;i++)
{
fa[i]=i;
}
while(k--)
{
scanf("%d%d%d",&type,&x,&y);
if(x>n||y>n||(x==y&&type==)){ //如果标号大于n 或者自己吃自己 肯定错
ans++;
continue;
}
if(find(x)!=find(y)) //如果父亲不同 不在同一集合 肯定不会错 现在合并(因为现在给出的信息已经是限制条件了)
{
baba(x,y,type); //合并的类型是type
}else{
if(type==) //如果是平级的
{
if((value[x]+p)%!=(value[y]+p)%){ //距离根节点的权值 取余3相等才合法(也就是和根节点的相食关系一致)
ans++; //不合法 加加
}
}else{
if((value[x]-value[y]+p)%==||(value[y]-value[x]+p)%==){
//合法就是x吃y,所以要么x比y大1,要么y比x大2(石头剪子布)
}else{
ans++;
}
}
}
}
cout<<ans<<endl;
}