P2024 [NOI2001]食物链 (带权并查集)

食物链

带权并查集,通过维护结点与根节点的距离 (代表相对关系),查询集合内点的关系;

在这里插入图片描述
由于题目描述只有三个物种,并且构成一个循环食物链,那么当知道了a与c 和 b与c 的关系后,就能推断出a与b的关系;在合并集合时,比如x吃y,那就让y做x的父节点,由此 若x->y->z->w,代表x吃y、y吃z、z吃w,w是根,此时能推断出 x 必然与 w 是同类(三个一循环)。

#include<iostream>
using namespace std;

int p[50010];
int d[50010];	//初始时,d[x] 都为0 代表 x 到其父节点p[x] 的距离

int find(int x){
	if(p[x] !=x) {
		int r = find(p[x]);
		d[x] += d[p[x]];	//在 find() 结束后 d[x] 已经更新成 x 到根节点的距离;
 		p[x] = r;
	}
	return p[x];	//路径压缩
}

int main()
{
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++) p[i] = i;
	int t,x,y;
	int ans=0;
	while(k--){
		cin>>t>>x>>y;
		if(x>n||y>n) ans++;
		else {
		    int px = find(x),py = find(y);
		    if(t==1){
			    if(px==py&&(d[x]-d[y])%3!=0) ans++;	//不是同类 
			    else if(px!=py){
			    	p[px] = py;
				    d[px] = d[y] - d[x];	//保证 d[x] == d[y] (同类) 注意这里的d[x]含义的不同;  
		    	}
		    }
    		else{
    			if(px==py&&(d[x]-d[y]-1)%3!=0) ans++;	//x不吃y 
    			else if(px!=py) {
    				p[px] = py;
    				d[px] = d[y] -d[x] +1;	// 保证d[x] = d[y] +1 
    			}
    		}
		}
	}
	cout<<ans<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值