• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
蓝桥杯-网络分析-带权并查集

网络分析

题目

网络分析

思路

​ 一开始考虑每次dfs, 然后进行memset(),复杂度为\(O(m \times N \times M)\), 只拿了50分, 看了网上的题解,如果不用带权并查集的话,维护并查集内所有的点,复杂度\(O(m \times N)\) 可以拿70分, 下面考虑正解带权并查集:

​ 我们可以维护一个祖宗节点作为子节点的偏移量, 然后对于子节点的发送数据,我们可以将其加入到祖宗节点中,最后求一个\(祖宗节点 + val[当前节点]\)的值就是答案,但是现在有一个问题我们需要维护,也就是合并问题,我们假设下图合并问题:

​ image-20230407190450897

如果我们现在要连接 A - B, 我们可以让其父亲节点相连,然后一段的节点减去新的祖宗节点的偏移量,也就能够维护合并。

image-20230407190713307

​ 这样我们能够使合并后的答案也是合法的。

代码

#include <iostream>
#include <vector>
#include <cstring>

using i64 = long long;

const int N = 1e4 + 10, M = 1e5 + 10;

int n, m;

int p[N], val[N];

int find(int x) {
 	if (p[x] == x || p[p[x]] == p[x]) return p[x];
 	
 	int r = find(p[x]);
 	val[x] += val[p[x]];
 	p[x] = r;

 	return r;
}


int main() {	
	std::cin >> n >> m;

	for (int i = 1; i <= n; i ++) {
		p[i] = i, val[i] = 0;
	}

	while (m --) {
		int op, a, b;

		std::cin >> op >> a >> b;

		int fa = find(a), fb = find(b);

		if (op == 1) {
			if (fa != fb) {
				p[fa] = fb;
				val[fa] -= val[fb];
			}
		} else {
			val[fa] += b;
		}
	}

	for (int i = 1; i <= n; i ++) {
		std::cout << ((find(i) == i)?(val[i]):(val[i] + val[find(i)])) << " \n"[i == n];
	}
}
posted on 2023-04-07 19:19  Jack404  阅读(33)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3