Kruskal重构树 学习笔记
Kruskal 重构树
最大生成树将部分内容倒置即可
回顾:Kruskal
基本信息
- 求解最小生成树
- 时间复杂度:\(O(m \log m)\)
- 更适合稀疏图
算法思想
- 按照边权从小到大排序
- 依次枚举每一条边,如果这一条边两侧不连通,则加入这条边
代码
点击查看代码
#include <bits/stdc++.h>
#define rr read()
using namespace std;
const int N = 200010;
inline int read()
{
int num = 0, flag = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-')
flag = -1;
for (; isdigit(ch); ch = getchar())
num = (num << 3) + (num << 1) + ch - '0';
return num * flag;
}
int f[N];
struct Edge
{
int a, b, w;
bool operator<(const Edge &W) const { return w < W.w; }
} g[N];
int find(int x) { return x == f[x] ? x : find(f[x]); }
int main()
{
int n = rr, m = rr;
int a, b, w;
for (int i = 0; i < m; ++i)
a = rr, b = rr, w = rr, g[i] = {a, b, w};
sort(g, g + m);
for (int i = 1; i <= n; ++i)
f[i] = i;
int res = 0, cnt = 0;
for (int i = 0; i < m; ++i)
{
int a = find(g[i].a), b = find(g[i].b), w = g[i].w;
if (a != b)
f[a] = b, res += w, ++cnt;
}
cnt < n - 1 ? printf("impossible\n") : printf("%d\n", res);
return 0;
}
Kruskal 重构树
算法思想
在构建最小生成树的时候,设现在枚举到了一条要加入最小生成树的边 \((u, v, w)\):
则在 Kruskal 重构树中,构建一个点权为 \(w\) 的虚点,编号为 \(t\),同时连边 \((u, t)\)、\((v, t)\)。
主要性质
- 重构树是一棵[二叉树];
- [子节点的点权]小于[父节点的点权](即大根堆);
- 最小生成树上[两点之间的最大边权]等于重构树上[两点之间的最大边权](即为重构树上两点 LCA 的点权)。
结论证明
最小生成树上两点间最大边权等于重构树上两点 LCA 的点权,证明:
- 后加入的边权一定小于先加入的边权,所以重构树一定自上到下点权不减;
- 两点在最小生成树上的路径的所有边一定都在重构树上两点之间;
- 所以两点在最小生成树上之间的最长边权一定是重构树上两点 LCA 的点权。
如图:

其中红色的点表示虚点,中间的数字表示其点权;白色的点表示原有的点。
代码
#include <bits/stdc++.h>
#define rr read()
using namespace std;
// INPUT GRAPH
const int N = 2e5 + 10;
const int M = 2e5 + 10;
// NEW GRAPH
const int NN = N + M;
const int MM = M + M;
// 4LCA
const int K = 20;
// FAST READ
inline int read()
{
int num = 0, flag = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-')
flag = -1;
for (; isdigit(ch); ch = getchar())
num = (num << 3) + (num << 1) + ch - '0';
return num * flag;
}
// NODE, EDGE, QUERY
int n, m, q;
// INPUT GRAPH
struct e
{
int u, v, w;
bool operator<(const e &t) const { return w < t.w; }
} g[M];
// UNOIN
int f[NN];
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
// NEW GRAPH
int d[NN], cnt;
int h[NN], e[MM], ne[MM], idx;
// 4LCA
int depth[NN];
int up[NN][K];
// ADD TO NEW GRAPH
inline void _add(int u, int v)
{
e[idx] = v;
ne[idx] = h[u];
h[u] = idx++;
}
void add(int a, int b, int w)
{
d[++cnt] = w;
f[a] = f[b] = cnt;
_add(a, cnt), _add(cnt, a);
_add(b, cnt), _add(cnt, b);
}
// LCA INIT
void init(int u, int fa)
{
depth[u] = depth[fa] + 1;
for (int i = 1; i < K; ++i)
up[u][i] = up[up[u][i - 1]][i - 1];
for (int i = h[u]; i != -1; i = ne[i])
{
int v = e[i];
if (v == fa)
continue;
up[v][0] = u, init(v, u);
}
}
// KRUSKAL
int kruskal()
{
sort(g + 1, g + 1 + m);
for (int i = 1; i <= n * 2; ++i)
f[i] = i;
cnt = n;
memset(h, -1, sizeof h);
int res = 0;
for (int i = 1; i <= m; ++i)
{
int u = find(g[i].u), v = find(g[i].v), &w = g[i].w;
if (u == v)
continue;
res += w, add(u, v, w);
}
init(cnt, 0);
return res;
}
// LCA
int lca(int x, int y)
{
if (depth[x] < depth[y])
swap(x, y);
for (int i = K - 1; i >= 0; --i)
{
if (depth[up[x][i]] >= depth[y])
x = up[x][i];
if (x == y)
return x;
}
for (int i = K - 1; i >= 0; --i)
if (up[x][i] != up[y][i])
x = up[x][i], y = up[y][i];
return up[x][0];
}
int main()
{
n = rr, m = rr;
int a, b, w;
for (int i = 1; i <= m; ++i)
a = rr, b = rr, w = rr, g[i] = {a, b, w};
q = rr;
int res = kruskal();
while (q--)
printf("%d\n", d[lca(rr, rr)]);
return 0;
}
资料来源
- https://www.luogu.com.cn/blog/lizbaka/kruskal-chong-gou-shu
- https://blog.csdn.net/m0_61735576/article/details/124804973
Kruskal重构树 学习笔记的更多相关文章
- kruskal重构树学习笔记
\(kruskal\) 重构树学习笔记 前言 \(8102IONCC\) 中考到了,本蒟蒻不会,所以学一下. 前置知识 \(kruskal\) 求最小(大)生成树,树上求 \(lca\). 算法详 ...
- Kruskal重构树学习笔记+BZOJ3732 Network
今天学了Kruskal重构树,似乎很有意思的样子~ 先看题面: BZOJ 题目大意:$n$ 个点 $m$ 条无向边的图,$k$ 个询问,每次询问从 $u$ 到 $v$ 的所有路径中,最长的边的最小值. ...
- P4197 Peaks [克鲁斯卡尔重构树 + 主席树][克鲁斯卡尔重构树学习笔记]
Problem 在\(Bytemountains\)有\(n\)座山峰,每座山峰有他的高度\(h_i\) .有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个困难值,这个值越大表示越难走, ...
- 洛谷P4197 Peaks&&克鲁斯卡尔重构树学习笔记(克鲁斯卡尔重构树+主席树)
传送门 据说离线做法是主席树上树+启发式合并(然而我并不会) 据说bzoj上有强制在线版本只能用克鲁斯卡尔重构树,那就好好讲一下好了 这里先感谢LadyLex大佬的博客->这里 克鲁斯卡尔重构树 ...
- [算法模板]Kruskal重构树
[算法模板]Kruskal重构树 kruskal重构树是一个很常用的图论算法.主要用于解决u->v所有路径上最长边的最小值,就是找到\(u->v\)的一条路径,使路径上的最长边最小. 图片 ...
- 【学习笔记】Kruskal 重构树
1. 例题引入:BZOJ3551 用一道例题引入:BZOJ3551 题目大意:有 \(N\) 座山峰,每座山峰有他的高度 \(h_i\).有些山峰之间有双向道路相连,共 \(M\) 条路径,每条路径有 ...
- [学习笔记]kruskal重构树 && 并查集重构树
Kruskal 重构树 [您有新的未分配科技点][BZOJ3545&BZOJ3551]克鲁斯卡尔重构树 kruskal是一个性质优秀的算法 加入的边是越来越劣的 科学家们借这个特点尝试搞一点事 ...
- 算法学习——kruskal重构树
kruskal重构树是一个比较冷门的数据结构. 其实可以看做一种最小生成树的表现形式. 在普通的kruskal中,如果一条边连接了在2个不同集合中的点的话,我们将合并这2个点所在集合. 而在krusk ...
- [luogu P4197] Peaks 解题报告(在线:kruskal重构树+主席树 离线:主席树+线段树合并)
题目链接: https://www.luogu.org/problemnew/show/P4197 题目: 在Bytemountains有N座山峰,每座山峰有他的高度$h_i$.有些山峰之间有双向道路 ...
- Kruskal重构树——[NOI2018] 归程
题目链接: UOJ LOJ 感觉 Kruskal 重构树比较简单,就不单独开学习笔记了. Statement 给定一个 \(n\) 点 \(m\) 边的无向连通图,用 \(l,a\) 描述一条边的长度 ...
随机推荐
- 一步步教你如何搭建K8S集群
一.环境配置 三台CentOS7虚拟机,默认配置,内存2GB.处理器2核心. 先更新下系统 1 sudo yum update 2 sudo yum upgrade 二.安装并启动 docker 1 ...
- 让优惠再续一年!SHPC 老客专享
最近云筏君经常收到自家小伙伴发来的关于产品活动的关心慰问,掐指一算,哦,原来是一年一度大家喜闻乐见的剁手节(学名"双十一")马上要来了! 大家都知道,云筏家的产品向来主打高性价比, ...
- delving into deep imbalanced regression翻译
非对照翻译,有所简略.翻译不对,尽情谅解,可留言 作者解释 and paper 笔记 Abstract Real-world data often exhibit imbalanced distr ...
- Vue_Django 登录注册+图书管理系统
Vue前端 注册页面 点击查看代码 <template> <div class="register"> <el-row :gutter="2 ...
- [ARM 汇编]高级部分—性能优化与调试—3.4.1 性能分析与优化策略
性能优化是嵌入式系统开发中的一个重要环节,尤其是在资源受限的环境下.性能优化的目标是提高代码执行速度.降低功耗和减少内存占用.在本章节中,我们将讨论性能分析与优化策略,并通过实例来学习如何应用这些策略 ...
- AuthenticationException异常无法被全局异常捕获的解决办法
我们可以先看一下为什么不能被捕获? 很明显JwtFilter的祖宗是Fliter,而我们自己定义的全局异常处理器@RestControllerAdvice 这个注解是 @ControllerAdvic ...
- ZEGO 即构音乐场景降噪技术解析
随着线上泛娱乐的兴起,语聊房.在线 KTV 以及直播等场景在人们的日常生活中占据越来越重要的地位,用户对于音质的要求也越来越高,因此超越传统语音降噪算法的 AI 降噪算法应运而生,所以目前各大 RTC ...
- Lock同步_小记
使用同步机制的这种方式解决线程安全问题,但是不知道具体的锁对象在哪里添加,并且锁对象在哪里释放锁对象,对于这种情况Jdk5以后Java提供了一个更具体的锁对象:Lock Lock 实现提供了比使用 s ...
- C语言链表实现(郝斌数链表学习笔记)
#include "stdafx.h" #include<stdio.h> #include<stdlib.h> typedef struct Node { ...
- web系统字典统一中文翻译问题
几乎每个web系统都离不开各种状态码.订单新建,待支付,未支付,已支付,待发货. 消息已读未读,任务待标记待审批已审批待流转已完成未完成.等等. 复杂一点的,会有多级状态码. 状态码超出3个的,一般都 ...