一个有趣的题目:并查集反集

赞助了大大的西瓜
题目连接
首先你要会并查集
这道题用到了一个有趣的思想:反集
就是在原数据的基础上乘2
也就是再作一个集合,多出来的n~~2*n作为辅助答案

	#include<iostream>
	using namespace std;
	int a[2010];
	int n, m;
	int findd(int x) { // 查找模板
		return x == a[x] ? x : a[x]=findd(a[x]);
	}
	void merge(int x, int y) { // 并查集模板
		x = findd(x), y = findd(y);
		if(x != y) a[x] = y;
	}
	int main() {
		cin >> n >> m;
		for(int i = 1; i <= 2*n; ++i) // 2倍数据
			a[i] = i;
		int x, y;
		char c;
		for(int i = 0; i != m; ++i) {
			cin >> c >> x >> y;
			if(c == 'F') {
				merge(x, y); // 普通合并
			} else {
				// 不能直接合并
				merge(x+n, y); // 先用反集分别保存一下
				merge(y+n, x);
				//如果a和b是敌人,合并n+b和a,n+a和b
				//如果c和a是敌人,合并n+c和a,n+a和c
				//那么b和c就并在一起了
				
				// 注意这里的合并祖先是 在 1~n
				// 如果写成merge(x, y+n) 祖先就在n~2*n里面了
				// 因为merge里面 a[x] = y
			}
		}
		int ans = 0;
		for(int i = 1; i <= n; ++i)
			if(a[i] == i) ans++;
		cout << ans << endl;
		return 0;
	}

第一次做这种题,感觉这反集思想蛮有趣的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

光—暗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值