【学习笔记】重链剖分

【学习笔记】重链剖分


关于树链剖分

树链剖分,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构来维护每一条链。

树链剖分其实分三种:重链剖分,长链剖分,实虚链剖分 ( ( L C T \rm LCT LCT ) )
所以,为了使整体显得更有条理(其实是我还没学完 ),我就分开写了。


重链剖分能做什么

1. 求最近公共祖先 L C A \rm LCA LCA
2. 修改节点 x x x 到节点 y y y 的最短路径上的所有节点 / / /边的权值。
3. 修改以节点 x x x 为根的子树中的所有节点 / / /边的权值。
4. 查询节点 x x x 到节点 y y y 的最短路径上的所有节点 / / /边的权值和或极值。
5. 查询以节点 x x x 为根的子树中的所有节点 / / /边的权值和或极值。


重链剖分的一些定义

定义 s i z e [ x ] \rm size[x] size[x] 为以 x x x 为根的子树的节点个数。

那么,对于每一个非叶节点,其所有儿子中 s i z e \rm size size 最大的儿子便为重儿子(如果有两个或以上都最大的话,则是其中随意一个),而 y y y 其它的儿子,都是轻儿子 。

一个节点连向其重儿子的边被称为重边,树中重边之外的边被称为轻边。多条重边相连为一条重链

放张图理解一下

在这里插入图片描述

图中灰心点为重儿子,白心点为轻儿子。加粗边为重边。
图中重链有 5 5 5 条: 1 — 3 — 7 — 13 — 16 — 18 , 12 — 15 , 10 — 14 , 2 — 5 , 4 — 8 1—3—7—13—16—18,12—15,10—14,2—5,4—8 137131618121510142548

性质
1. 若 x x x 为轻儿子,则有 s i z e [ x ] \rm size[x] size[x] < = <= <= s i z e [ f a t h e r [ x ] ] 2 \rm \dfrac{size[father[x]]}{2} 2size[father[x]]
2. 从根到某一点的路径上不超过 log ⁡ 2 n \rm \log_2 n log2n 条重链,不超过 log ⁡ 2 n \rm \log_2 n log2n 条轻链。(最重要的性质)


重链剖分的实现

预处理

定义 h s o n i \rm hson_i hsoni 表示节点 i i i 的重儿子编号, s i z i \rm siz_i sizi 表示以节点 i i i 为根的子树的节点个数, d e p i \rm dep_i depi 表示节点 i i i 的深度, f a i \rm fa_i fai 表示节点 i i i 的父亲节点, t o p x \rm top_x topx 表示节点 i i i 位于的重链上的顶端节点标号, d f n i \rm dfn_i dfni 表示 d f s \rm dfs dfs 进入节点 i i i 的时间戳, t t r i \rm ttr_i ttri i i i d f s \rm dfs dfs 序里在树上对应的节点编号。

第一个 d f s \rm dfs dfs 先求出每个节点的 f a i \rm fa_i fai h s o n i \rm hson_i hsoni s i z i \rm siz_i sizi 、和 d e p i \rm dep_i depi
第二个 d f s \rm dfs dfs优先走重边为原则,遍历出 d f s \rm dfs dfs,同时求出每个节点的 t o p x \rm top_x topx d f n i \rm dfn_i dfni t t r i \rm ttr_i ttri

比较重要的两点:
1. 优先走重边——每一条重链的新编号是连续的。
2. d f s \rm dfs dfs 序 ——同一棵子树所对应的一定是dfs序中连续的一段。

还是那张图
在这里插入图片描述
P S : \rm PS: PS: 红字表示点的 d f s \rm dfs dfs 序。 d f s \rm dfs dfs 序为: 1 , 3 , 7 , 13 , 16 , 18 , 17 , 12 , 15 , 6 , 10 , 14 , 2 , 5 , 4 , 8 , 9 1,3,7,13,16,18,17,12,15,6,10,14,2,5,4,8,9 1,3,7,13,16,18,17,12,15,6,10,14,2,5,4,8,9

维护以及在线操作

修改操作

1. 对于修改节点 x x x 到节点 y y y 的最短路径上的所有节点 / / /边的权值,可以像求 L C A \rm LCA LCA一样边跳便更改权值。
2. 至于修改以节点 x x x 为根的子树中的所有节点 / / /边的权值,只需要修改 d f n x \rm dfn_x dfnx d f n x + s i z x − 1 \rm dfn_x+siz_x-1 dfnx+sizx1

查询操作

与修改操作类似,只是把修改变为查询。

时间复杂度?

用线段树来维护树链剖分的时间复杂度是 O ( n + q log ⁡ 2 2 n ) {\rm O}(n +q\log_2^2n)

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值