Kruskal重构树 学习笔记

文章目录

  • Kruskal重构树 学习笔记
    • 前言
    • 例题1 BZOJ3732 Network
    • 例题2 [NOI2018] 归程

前言

Kruskal重构树是一种比较冷门的算法,但在解决某些问题时相当好用。

例题1 BZOJ3732 Network

链接

在一个 nnn 点 mmm 边的无向连通图中多次询问两点间的最长边最小值(即两点间的瓶颈)。

这是一个经典的 Kruskal重构树问题。

这个问题其实也可以直接用最小生成树来解决。因为要最小化最长边,选择最小生成树上的边肯定是不劣的。于是我们可以在最小生成树上倍增得到答案。

而Kruskal重构树则是这样的做的:在用Kruskal合并连通块时,顺便维护一个树的结构。比如要合并连通块 fufufu 和 fvfvfv,中间有 权值为 www 的边相连,就新建一个节点作为 合并后连通块的根,赋予点权为 www,并且设置左右儿子为 fufufu 和 fvfvfv。Kruskal做完后,我们就构造了具有以下特征的树:

  1. 叶子节点是原图的 nnn 个点,没有点权。
  2. 非叶子节点代表着原图中 在生成树上的 n−1n-1n−1 条边,点权就是原图的边权。
  3. 由于合并时边权有一定次序,我们发现得到的树是个二叉堆(不考虑叶子节点)。如果是做最小(大)生成树,得到的是大(小)根堆。
  4. 两点于树上的路径上的各点,相当于原图上两点走最小(大)生成树的路径上的各边。

这个树叫做 Kruskal重构树。易得这棵树一共有 2n−12n-12n−1 个点, 2n−22n-22n−2 条边。


回到这题。很容易知道,我们要找的,就是在 Kruskal 重构树上两点路径中的最长边。或者准确点,两点路径上的点权最大者。别犯浑用倍增做啊!由于 Kruskal 重构树是个堆,点权最大的就是两点的 lca 了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
ll read() {ll x = 0, f = 1; char ch = getchar();for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');return x * f;
}
const int MAXN = 30005;
const int MAXM = 60005;
int n, m, k, num, upto[MAXN], val[MAXN], head[MAXN], ver[MAXM], nxt[MAXM], cnt, dep[MAXN], sz[MAXN], fa[MAXN], son[MAXN], top[MAXN];
struct Edge {int u, v, w;}e[MAXM];
bool cmp(const Edge& a, const Edge& b) {return a.w < b.w;}
int getup(int u) {return u == upto[u] ? u : upto[u] = getup(upto[u]);}
void addedge(int u, int v) {ver[++cnt] = v; nxt[cnt] = head[u]; head[u] = cnt;}
void Kruskal() {num = n;sort(e + 1, e + 1 + m, cmp);for(int i = 1; i <= n; i++) upto[i] = i;for(int i = 1; i <= m; i++) {int fu = getup(e[i].u), fv = getup(e[i].v);if(fu == fv) continue;val[++num] = e[i].w; upto[num] = upto[fu] = upto[fv] = num;addedge(fu, num); addedge(num, fu); addedge(fv, num); addedge(num, fv);}
}
void dfs1(int u, int f) {dep[u] = dep[f] + 1; sz[u] = 1; fa[u] = f; son[u] = 0;for(int i = head[u]; i; i = nxt[i]) if(ver[i] != f) {int v = ver[i]; dfs1(v, u); sz[u] += sz[v];if(sz[v] > sz[son[u]]) son[u] = v;}
}
void dfs2(int u, int tprt) {top[u] = tprt; if(son[u]) dfs2(son[u], tprt);for(int i = head[u]; i; i = nxt[i]) if(ver[i] != fa[u] && ver[i] != son[u]) {int v = ver[i]; dfs2(v, v);}
}
int Lca(int u, int v) {while(top[u] != top[v]) {if(dep[top[u]] < dep[top[v]]) swap(u, v);u = fa[top[u]];}return dep[u] > dep[v] ? v : u;
}
int main() {n = read(); m = read(); k = read();for(int i = 1; i <= m; i++) e[i].u = read(), e[i].v = read(), e[i].w = read();Kruskal();int rt = getup(1);dfs1(rt, 0); dfs2(rt, rt);for(int i = 1; i <= k; i++) {int a = read(), b = read();printf("%d\n", val[Lca(a, b)]);}return 0;
}

例题2 [NOI2018] 归程

链接

这道题与 Kruskal重构树无关的部分我直接写了篇题解,这里仅提一下这样一个小问题:

在一个无向连通图中多次询问,每次给出点 vvv 和限制 ppp, 请回答仅经过边权 ≤p\le p≤p 的边可以到达点的个数。(和原题稍有转化)

这是另一个 Kruskal 重构树的模型。

这个问题似乎不好做,不过有个简单易行的离线做法。按限制把询问升序排序,在做最小生成树的同时回答询问即可。

在线做法?我只知道Kruskal重构树,可能是我太菜

我们建完Kruskal重构树后,问题就转化为:不经过点权 >p>p>p 的点,最多可以到多少个点。然后由于它是一棵树,我们能去的点都在一个子数内。倍增找到深度最小的 点权≤p\le p≤p 的点,询问子树信息即可。

Kruskal重构树 学习笔记相关推荐

  1. 【NOI 2018】归程(Kruskal重构树)

    题面在这里就不放了. 同步赛在做这个题的时候,心里有点纠结,很容易想到离线的做法,将边和询问一起按水位线排序,模拟水位下降,维护当前的各个联通块中距离$1$最近的距离,每次遇到询问时输出所在联通块的信 ...

  2. Kruskal重构树详解

    目录 Kruskal算法 Kruskal重构树 在学习重构树之前,我们要先熟悉一下基本的kruskal算法 Kruskal算法 首先给出一张有向图,让我们求最小生成树(用总权值最小的一些边的集合,使得 ...

  3. kruskal重构树练习

    洛谷 P4197 Peaks 题意: 有 nnn 个山峰,每一个山峰高 hih_ihi​ ,有 mmm 条双向带权边将一些山峰连接起来,有 qqq 次询问,每次询问 (v,x,k)(v,x,k)(v, ...

  4. 洛谷P4768 [NOI2018]归程(Kruskal重构树)

    题意 直接看题目吧,不好描述 Sol 考虑暴力做法 首先预处理出从$1$到每个节点的最短路, 对于每次询问,暴力的从这个点BFS,从能走到的点里面取$min$ 考虑如何优化,这里要用到Kruskal重 ...

  5. kruskal 重构树(讲解 + 例题)

    kruskal重构树 如何建树 模仿kruskalkruskalkruskal,先将所有边排序. 依次遍历每一条边,如果这条边的两个节点(u,vu, vu,v)不在同一个连通块里面, 则新建一个nod ...

  6. Network 黑暗爆炸 - 3732 倍增lca || Kruskal重构树

    传送门 文章目录 题意: 思路: 题意: 思路: 两点间最长边最小值一定是最小生成树上两点间的最大值,这个比较容易证,就不多说了. 知道这个结论后, 我们直接跑一个KruskalKruskalKrus ...

  7. [ONTAK2010] Peaks加强版 (kruskal重构树+主席树+倍增)

    Peaks description solution code description 在Bytemountains有N座山峰,每座山峰有他的高度h_i 有些山峰之间有双向道路相连,共M条路径,每条路 ...

  8. [NOI2018] 归程(线段树维护并查集的可持久化/kruskal重构树,倍增+dijkstra最短路)

    [NOI2018] 归程 description solution1 code1 solution2 code description 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要 ...

  9. AGC002(D~F)【Kruskal重构树,博弈论,dp】

    正题 AT1998 [AGC002D] Stamp Rally[Kruskal重构树,倍增] https://www.luogu.com.cn/problem/AT1998 题目大意 给出nnn个点m ...

最新文章

  1. ubuntu访问win7
  2. python 线程指南
  3. docker学习------centos7.5下的swarm集群可视化构建
  4. VMware借微软之东风紧追思杰XenApp业务
  5. wordpress 根据文章ID获取分类ID和标签ID
  6. +++++++子域授权与编译安装(一)
  7. ftp网页服务器不允许匿名登录,我的FTP服务器不让匿名登陆,怎么办?
  8. 线上环境 Linux 系统调用追踪
  9. linux之xargs使用技巧
  10. Java之品优购课程讲义_day08(7)
  11. C++ string类相关函数
  12. erl_nif中解决调用enif_get_XX错误问题
  13. [深入Maven源代码]maven绑定命令行参数到具体插件
  14. offer拿到手软,java分布式面试题及答案
  15. 数据库无限层级分类设计
  16. 驱动人生、驱动精灵等绿色去广告单文件版合集
  17. python实现京东联盟API接口对接
  18. 有监督学习、无监督学习和半监督学习的分类
  19. namecheap,namesilo域名注册优势,国外域名注册,2018 namesilo注册优惠码
  20. java电子邮件收发系统,基于Java_Mail的电子邮件收发系统毕业设计

热门文章

  1. 08.29web自动化测试
  2. WIN10__针对SMB的那啥
  3. 购房指南—新房交房注意事项细节有哪些
  4. dblink导致存储过程报异常ORA-03113:通信通道文件尾 ORA-02063紧接着line(xxxdblink名称) ORA-06512在(xxxx)line 24
  5. 巨头都在追逐的眼球追踪技术,究竟能带来什么?
  6. 19南大软院上岸学姐考研经验分享
  7. 好好讲一讲,到底什么是Java高级架构师!
  8. 公钥基础设施 PKI 技术与应用发展
  9. MySql 如何查询某一天内的数据
  10. 纽约州立大学环境与林业学院计算机科学专业,纽约州立大学环境与林业科学 治理环境是全球需要面对的问题...