长链剖分可以把维护子树中只与深度有关的信息做到线性的时间复杂度。
例题cf1009f
给一棵树,定义每个点的dom值为,以该点为根的子树重中,节点数最多的那一层的层数,即那一层距离这个根节点有几条边,如果多层节点数相同,取最小的层数。例如单独叶节点的dom值是0,一条垂直的链的dom值也是0(每层数量都是1,取最前面的)
定义dp[i][j]为i树第j层的节点数,如果暴力遍历复杂度是n^2。我们用类似启发式合并的思想,对于长链(最深而非最重的链)处理后的结果直接拿给父节点用,然后再去依次解决轻节点,并把这些轻节点向父节点暴力合并。由于所有的轻链合并到深链上之后就“失效”了,之后再也用不到,所有整体时间复杂度只有O(n)。(太nb了这个算法……
由于剖分的性质,一条链上的节点在一个区间,子树的节点也都在一个区间,所以dp数组不必为难开n^2大小,我们考虑用指针实现,这样也实现了重儿子O(1)传递dp数组给父亲,实际上就是用了同一块内存,重儿子跑完了直接父亲就顺着用(看代码吧。
1 |
|