一、概述
所谓树链剖分,就是把树上的路径进行重链、轻链的划分
它并不是一个复杂的算法或者数据结构,只是能把一棵树拆成链来处理而已
换句话说,树链剖分只是 xx 数据结构 / 算法在树上的推广
定义 size[v] 为以 v 为根节点的子树节点的个数,引入一些概念
重儿子(Preferred Child):令 u 为 v 的儿子中 size 最大的节点,那么 u 就是 v 的重儿子,一个节点最多只能有一个重儿子
重(zhòng)边(Preferred Edge):连接父亲节点和重儿子的边
重链(Preferred Path):由重边及重边连接的节点构成的链
显然有如下性质:
如果 (v, u) 不为重边,则 size[u] * 2 < size[v]
从根节点到某一节点的路径上,重边和轻边的数量都不超过 logn 条
二、解决的问题
维护一棵树,支持下列操作:
链上求和
链上求最值
链上修改
子树修改
子树求和
换根
三、实现
1、首先进行如下定义
size[v] :以 v 为根节点的子树节点的个数
depth[v] :节点 v 的深度(根节点的深度为 1)
top[v] :v 所在链的顶端节点
father[v] :v 的父亲节点
son[v] :v 的重儿子结点
id[v] :v 在线段树中的位置(基于点的重编号)
key[pos] :线段树 pos 位置上所存储的点(基于点的重编号)
2、分两次 dfs 进行剖分
第一次 dfs:
求出所有的节点的 size、depth、size、son、father
第二次 dfs:
求出所有节点的 top、id 以及线段树所有位置上的点
dfs 过程中保证重链各边在线段树中连续分布
对于非叶子节点 v,显然有 top[son[v]] = top[v],对于 v 的轻儿子 u,有 top[u] = u
修改操作
(1)如果节点 u、v 不在同一条重链上,就不断修改至 u、v 处于同一条重链
(2)如果节点 u、v 在同一条重链上,直接进行修改
求和、求最值操作与修改操作类似
四
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include