杭电3635——(带权)并差集

杭电3635——(带权)并差集

原题传送门并差集模板函数介绍大佬的并差集详解

写在题前:
这个题用的并差集需要带权值,刚开始不是那么容易理解,不过你转过那个弯就很简单了。

解题步骤:
1、转移龙珠的时候:

  • 先找到当前龙珠的位置,再将这个位置的所有龙珠放在另一个位置。

2、查询的时候:

  • 直接访问数组就行。

写在题后:
我本来以为输入数据可能会出现环的情况,好不容易写完了,结果wa了,后来才发现输入的数据根本不会出现有环的情况,坑死人!!!

ac代码:

# include <iostream>
# include <algorithm>
# include <cstdio>
# include <cstdlib>
# include <string>
# include <cstring>
# include <vector>
using namespace std;

const int maxn = 10010;
int id[maxn];//id[x]:龙珠x所在的城市
int num[maxn];//num[x]:城市x龙珠的数量
int cnt[maxn];//cnt[x]:龙珠x移动的次数

int fin(int x) {//找到龙珠x所在的城市,需要用路径压缩
/*
fin函数流程:
	我们可以将fin函数看做两个部分,一个是路径压缩,一个是cnt数组的更新,
	cnt的更新是在寻找最上面节点的过程中更新的,
  流程如下:
	如果id[x]等于x,说明龙珠x在城市x这里,直接返回;
	如果不等,用t记录id[x]的值,用于更新cnt数组
	令id[x]=fin(id[x]),(用了递归);
	然后让cnt[x]在本来的基础上加上cnt[t]的值;
	返回id[x]的值。
cnt更新的具体流程(就是递归的一个过程):
	举个例子:1的上面是2,2的上面是3,3的上面是4,4就是最上面的节点。
	需要我们更新4个节点的cnt值,正常的顺序应该是4->3->2->1,从上往下更新的
	但是我们没办法从上往下遍历,只能从下往上遍历,因此我们可以这样做;
	我们从1开始,
	发现1上面有2,找2,{
		发现2上面有3,找3,{
			发现3上面有4,找4,{
				发现4上面没有节点,直接返回
			}
			将cnt[3]在自己的基础上加上cnt[4]的值,
		}
		将cnt[2]在自己的基础上加上cnt[3]的值,
	}
	将cnt[1]在自己的基础上加上cnt[2]的值,
*/
	if(id[x] == x) {
		return id[x];
	}
	int t = id[x];
	id[x] = fin(id[x]);
	cnt[x] += cnt[t];
	return id[x];
}
void meg(int x, int y) {
	int a = fin(x);
	int b = fin(y);//找到龙珠x所在的城市a,找到龙珠y所在的城市b
	if (a !=b) {
		id[a] = b;//将城市a父亲是城市b,连接的过程。
	}
	num[b] += num[a];//城市a的龙珠全给城市a
	num[a] = 0;//城市a的龙珠清零。
	cnt[a] ++;//龙珠a移动次数加一
}
bool same(int x, int y) {
	return fin(x) == fin(y);
}

int main() {
	ios::sync_with_stdio(false);
	int T;
	cin >> T;
	for (int ti = 1; ti <= T; ti++) {
		cout << "Case " << ti << ":" << endl;
		for (int i = 0; i < maxn; i++) {
			id[i] = i;
			num[i] = 1;
		}
		memset(cnt,0,sizeof (cnt));
		//注意清空数据。
		
		int m, n;
		cin >> n >> m;
		while(m--) {
			string str;
			cin >> str;
			if (str[0] == 'T') {
				int x, y;
				cin >> x >> y;
				meg(x, y);
			}
			else if (str[0] == 'Q') {
				int t;
				cin >> t;
				int x = fin(t);
				cout << x << " " << num[x] << " " << cnt[t] << endl;
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值