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

本文介绍了一种使用并查集数据结构解决生物关系问题的方法,将生物关系分为同类、猎物和天敌三类,通过维护这些关系来判断陈述的真实性。代码实现了输入生物数量和关系陈述后的真假判断,适用于处理A、B、C三种生物间的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

解题思路:将并查集分为三个部分 分别是同类,猎物 ,天敌,取x(x属于1~n)举个栗子,与x一块的为x的同类,与x+n为一块的为x的猎物,与x+2*n为一块的为x的天敌。我们只需要同时维护这三个部分,并用来判断假话即可。由于只有A,B,C三种动物,那么A猎物的猎物就是A的天敌这需要注意维护。代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int maxn=5e4+5;
int fa[maxn*3],rk[maxn*3]; //一部分代表同类, 二猎物 ,三天敌 
int n,k,ans=0;
void init(){
	for(int i=0;i<maxn*3;++i)
		fa[i]=i,rk[i]=1;
}
int find(int x){
	if(x==fa[x])	return fa[x];
	else return fa[x]=find(fa[x]);
}
bool ck(int x,int y){
	x=find(x),y=find(y);
	if(x==y)	return true;
	else return false;
}
void unite(int x,int y){
	x=find(x),y=find(y);
	if(rk[x]<rk[y])	fa[x]=y;
	else{
		if(rk[x]==rk[y])	rk[x]++;
		fa[y]=x;
	}
}

int main(){
	std::ios::sync_with_stdio(0);
	init();
	cin>>n>>k;
	int x,y,z;
	for(int i=1;i<=k;++i){
		cin>>z>>x>>y;
		if(x>n || y>n){
			ans++;
			continue;
		}
		if(z==1){ //同类 
			if(find(x+n)==find(y) || find(x+2*n)==find(y) ){
                //y是x的猎物 或者 y是x的天敌 即为假话
				ans++;
				continue;
			} 
			unite(x,y),unite(x+n,y+n),unite(x+2*n,y+2*n);
            //x的同类也是y的同类合并,猎物和天敌同理
		}
		else if(z==2){ //x吃y 
			if(find(x)==find(y) || find(x)==find(y+n)){
                //x与y是同类 或者 y的猎物有x
				ans++;
				continue;
			}
			unite(x+n,y),unite(x,y+2*n),unite(x+2*n,y+n);
            //x的猎物与y是同类 x的同类是y的天敌 x的天敌是y的猎物 
		}	
	}
	cout<<ans<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值