【NOI 2001】食物链

已经不想复制链接了…
看到题目后,没学过并查集的话会想到用3个数组,每个询问都查询或添加,可看一看这惊人的数据,emmm还是算了吧。(我当时就是这么想的
学了并查集后,也发现这不是普通的并查集,虽然有判断是否一个种类,可无法判断是否互相吃。这时候就该引出你了,虚点!
将一个点扩大成3个点(按题目而定,如果点较多,虚点也无能为力),将A,B,C的关系转换成这样:

设A被A+n吃,A+n被A+n2吃,A+n2被A吃,B与C以此类推,则可将
A,B+n,C+n2为一类
A+n,B+n
2,C为一类
A+n*2,B,C+n为一类

然后,就好了吧。

#include<cstdio>
const int N = 50000;
int n, T, ba[N * 3 + 5], f, u, v, ans;
void makeSet() {
	for(int i = 1; i <= n * 3; i ++)
		ba[i] = i;
}
int findSet(const int x) {
	return x == ba[x] ? x : ba[x] = findSet(ba[x]);
}
void unionSet(const int x, const int y) {
	ba[findSet(x)] = findSet(y);
}
int main() {
	scanf("%d %d", &n, &T);
	makeSet();
	while(T --) {
		scanf("%d %d %d", &f, &u, &v);
		if(u > n || v > n || (u == v && f == 2)) {
			ans ++;
			continue;
		}
		if(f == 1) {
			if(findSet(u) == findSet(v + n) || findSet(u) == findSet(v + (n << 1)))
				ans ++;
			else {
				unionSet(u, v);
				unionSet(u + n, v + n);
				unionSet(u + (n << 1), v + (n << 1));
			}
		}
		else {
			if(findSet(u) == findSet(v) || findSet(u) == findSet(v + (n << 1)))
				ans ++;
			else {
				unionSet(u, v + n);
				unionSet(u + n, v + (n << 1));
				unionSet(u + (n << 1), v);
			}
		}
	}
	printf("%d\n", ans);
	return 0;
}

注:判断时判断是否一类而非不同类,因为先开始大家都是不一样的。
如果有不对的地方,请大佬指出哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值