0
点赞
收藏
分享

微信扫一扫

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

黎轩的闲暇时光 2022-03-11 阅读 74

题目链接

题意:

一共有三类动物,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[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 条评论