超级Trick—Kruskal重构树学习笔记

在读这篇文章之前,请确保你会Kruskal(最小生成树)算法与树上LCA算法。

引入

Description

给定一棵树,边带权,每次查询两点间经过的所有边的长度的最小值。

虽然本题可以采用时间复杂度优秀的树剖+RMQ或树上倍增,但是本题也可以采用Kruskal重构树的方法解决

Solution

首先,我们将树上的边按照权值从小到大排序。考虑建立出一棵新树:

从前往后扫一遍边。假设当前扫到的边连接了节点 u , v u,v u,v 且边权 w w w。若加入 u , v u,v u,v这条边后不会出现环(即为最小生成树的树边),那么我们就建立一个新点 p p p,将 p p p 分别连向 u , v u,v u,v 所在集合的代表,并令点 p p p 的权值为 w w w ;最后我们将 u , v u,v u,v 所在集合的代表连向 p p p 。并查集维护即可。

建立出来的这棵树被称为"Kruskal重构树"。它有一个重要的性质

⌊ \lfloor 这棵树是一个二叉树;更进一步的,也是一个大根堆/小根堆 ⌉ \rceil

因此,对于一次形如 ( x , y ) (x,y) (x,y) 的询问,答案为新树上 LCA ( x , y ) \text{LCA}(x,y) LCA(x,y) 的点权。

时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)

例题

例1(Luogu P4197)

Description

在这里插入图片描述
1 ≤ n ≤ 1 0 5 , 1 ≤ m , q ≤ 5 × 1 0 5 , h i , c , x ≤ 1 0 9 1\le n\le 10^5, 1 \le m,q \le 5×10^5, h_i,c,x \le 10^9 1n105,1m,q5×105,hi,c,x109

Solution

首先我们建立出这个图的Kruskal重构树。

不难发现,一次询问中所有满足要求的点均在以 r r r 为根的子树中。 r r r 可以通过倍增求出。

于是现在问题变为:静态查询子树中的点权第 k k k 小值。这显然可以使用 dfs 序+主席树维护,

注意 h h h 需要离散化。时间复杂度为 O ( ( n + m ) log ⁡ n ) O((n+m) \log n) O((n+m)logn)

配套练习题

[NOI2018 D1T1]归程

提示: 关于最大生成树的重构树+图论/倍增的综合题

例2

Description

给定一棵大小为 n n n无向图。你需要执行 q q q次询问或操作:

1 u: 令所有与 u u u连通的节点中点权最大的节点是 v v v,你需要将 v v v的点权变为 0 0 0并输出 v v v
2 x y: 删除从 x x x y y y的无向边。保证这条边存在。

n , q ≤ 5 × 1 0 5 n,q \le 5 \times 10^5 n,q5×105,时限 2s \text{2s} 2s

Solution

动态删边,动态查询点权的最大值……我们自然而然地想到了LCT。可惜这个东西的常数非常大;换句话说,这个东西的时间复杂度并不正确。我们需要一种常数较小的单 log ⁡ \log log 做法。

考虑给每条边一个权值,表示它被删除的时刻。特别的,永远没有被删除的边的权值为 ∞ ∞ 。于是,第 i i i 次询问就变为了“查询仅经过权值不小于 i i i 的边所能到达的最小点权”。

我们建出 Kruskal 重构树,此时问题变为:单点修改,查询子树最小值位置。我们建立一棵线段树,每个节点维护其对应区间的点权最大值点权最大值的位置

时间复杂度 O ( ( n + m ) log ⁡ m ) O((n+m) \log m) O((n+m)logm)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值