首页 > 代码库 > 树链剖分小结
树链剖分小结
这两周在学树剖。
先扔个模板
有一类题目,要求实现一类在树上的操作,比如:
修改/求 树上某 节点/边权 的(最)值;
修改/求 树上某 节点/边权 及其子树上所有节点的(最)值;
修改/求 树上某两点路径间的 节点/边权 的(最)值;
乍一看似乎用线段树就可以实现,但是如果仔细想想,可以发现单凭线段树是无法解决的。
对于这类题目,常用的解决方法是树链剖分。
树链剖分(节选自starszys博客):
相关定义:
重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子。
轻儿子:v的其它子节点。
重边:点v与其重儿子的连边。
轻边:点v与其轻儿子的连边。
重链:由重边连成的路径。
轻链:轻边。
树链,就是树上的路径。剖分,就是把路径分类为重链和轻链。
记siz[v]表示以v为根的子树的节点数
d[v]表示v的深度(根深度为1)
top[v]表示v所在的重链的顶端节点
f[v]表示v的父亲
son[v]表示与v在同一重链上的v的儿子节点(重儿子)
id[v]表示:
1.v与其父亲节点的连边(v的父边)在线段树中的位置;
2.v在线段树中的位置;
只要把这些东西求出来,就能用logn的时间完成上述问题中的操作。
实际上,只需要两次dfs就可以求出上述变量。
dfs1(dfs):求出f、d、siz、son、top、id
dfs2(build):求出id与top(详见模板)
然后将原树中各点的值update到线段树中,进行各种操作。
时间复杂度:
既然树剖这么好用,那它的时间复杂度如何呢?
可以证明,树链剖分的时间复杂度是O(N·logn·logn)。
经过上面的学习,可以发现树链剖分的结构是沿着链向上跳+线段树修改/查询。
线段树的时间复杂度是O(N·logn),而在树链上每走一条轻边,子树大小就/=2,所以最多走log n条轻边。
推荐题目:
模板题:BZOJ4034、BZOJ1036(LZOJ21004)、BZOJ2243、POJ3237
稍难:BZOJ3531、BZOJ3626、NOIp2015day1T3、NOIp2016天天爱跑步
树链剖分小结