【AcWing 240. 食物链 】带权并查集

题目链接

题意:

一共有三类动物,A,B,C,有这么一种关系A吃B,B吃C,C吃A,现在给你N个动物,M个关系,问有多少个关系是错误的。输入的格式为 op x y,当op = 1时表示 x 和 y 是同类,当op = 2时表示 x 吃 y。

分析:

这个题很明显的就是带权并查集了,边的权重代表的是到这个集合的根节点的距离,当x到根节点的距离比y少1的时候就代表x吃y,现在有d数组表示点到其父节点的距离时隔两年的更新: 之前我理解的是到其根节点的距离,其实是不正确的,因为路径压缩后其父节点就变成根节点了,所以说可以直接说成是根节点,但是其实是父节点,然后更新的时候是d[x] += d[fa[x]],假如他和他父亲隔着d[x],然后他父亲和他父亲的父亲隔着d[fa[x]],那么他到他爷爷不就是d[x]+d[fa[x]]吗,只不过因为路径压缩的原因把这一系列的思考浓缩成了一个语句,当时说实话没太明白怎么搞的,现在重新审视一下这道题,确实有更深的理解和思考了)
,若(d[x]-d[y]+3)%3 = 0表示x和y是同类,若(d[x]-d[y]+3)%3=1表示y吃x,现在先看一张图片吧
在这里插入图片描述
现在如果是x吃y的关系,那么最后的结果就是(dx - dy + 3) % 3 = 1,那么合并fx和fy的话就是:
?+dx+1=dy,那么? = dy-dx-1,所以说更新的时候就是(dy-dx-1+3)%3,集合合并的前提是x和y不在同一个集合内,那么就能结合,如果x和y在一个集合内的话就要判断一下dy和dx的关系了,下面请看代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<climits>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef unsigned long long ull;
const int mod = 1e9+7;
const int N = 50010;
int fa[N],d[N],n,m;
int find(int x){
//	if(x != fa[x]){
//		int t = find(fa[x]);
//		d[x] = (d[x] + d[fa[x]]) % 3;
//		fa[x] = t;
//	}
	if(x!=fa[x])
	{
		int t=fa[x];
		fa[x]=find(fa[x]);
		d[x]=(d[x]+d[t])%3;
	}
	return fa[x];
}
int main(){
	cin>>n>>m;
	int ans = 0;
	for(int i=1;i<=n;i++) fa[i] = i;
	for(int i=1;i<=m;i++){
		int op,x,y;
		cin>>op>>x>>y;
		if((x > n || y > n) || (x == y && op == 2)){
			ans++;
			continue;
		}
		int c = (op==2)?1:0;
		int pa = find(x),pb = find(y);
		if(pa == pb){
			if(op == 1 && d[x] != d[y]) ans++;
			if(op == 2 && (d[x] - d[y] + 3) % 3 != 2) ans++;
		}
		else{
			fa[pa] = pb;
			d[pa] = (d[y] - d[x] - c + 3) % 3;
		}
	}
	cout<<ans<<endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇智波一打七~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值