[算法学习] 长链剖分

Posted wlzhouzhuan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[算法学习] 长链剖分相关的知识,希望对你有一定的参考价值。

简介

长链剖分是跟dsu on tree类似的小(trick),可以资瓷维护子树中只与深度有关的信息
并能达到线性的时间复杂度。

算法流程

对于每个点,记录重儿子(heavy[u])表示深度最大的儿子,其余作为轻儿子
这样我们可以得到若干条互不相交的长链。
在维护信息的过程中,我们先(O(1))继承重儿子的信息,再暴力合并其余轻儿子的信息。
因为每一个点属于一条长链,且一条长链只会在链顶位置作为轻儿子暴力合并一次,所以复杂度是线性的。
但是我们发现,这个数组仿佛开不下(大雾),所以我们需要想想办法来解决。
有一个比较巧妙的方法,就是利用指针来实现。
下面以一道题为例。

CF1009F Dominant Indices

题目链接:CF1009F Dominant Indices

Description

给定一个以 (1) 为根, (n) 个节点的树。
(d(u,x))(u) 子树中到 (u) 距离为 (x) 的节点数。
求对于每一个点,最小的 (k) ,使得 (d(u,k)) 最大。
数据范围 (1le nle 10^6)

Solution

我们先考虑如何暴力做。
定义(f_{u,i})表示在 (u) 的子树内,到 (u) 的距离为 (i) 的点的个数。
那么,我们不难推出转移方程: (f_{u,0}=1,f_{u,i}=sum_{vin son(x)}f_{v,i-1})
复杂度:(O(n^2)),需要进行优化。
我们定义(heavy[u])表示深度最大的儿子,(len[u])表示(x)到儿子的最长距离。
不难发现(dp)第二维的 (i) 肯定不超过 (len[u])
为避免数组存不下的问题,我们采用指针来代替,即对于每条长链的链顶给它一个长度为(len[x])的内存。
这样的好处在于,对于一条长链,我们可以直接让父亲点从子节点那里继承答案。
对于非重儿子的点,我们暴力合并链即可。
很显然,每条链只会被合并一次,因此复杂度是线性的。
复杂度:(O(n)),可以通过本题。

Code

以上是关于[算法学习] 长链剖分的主要内容,如果未能解决你的问题,请参考以下文章

树链剖分(轻/重链剖分学习笔记)

长链剖分总结

长链剖分随想

省选前学习计划

模板K级祖先(长链剖分)

长链剖分 解 k级祖先问题