树链

来源:互联网 发布:eclipse打war包源码 编辑:程序博客网 时间:2024/05/17 06:03

树链剖分(heavy path decomposition,轻重路径剖分),我个人认为,相比起称之为一种“算法”,更像是一种处理树的相关问题时的一种方法,技巧。
其实,真正的树链剖分,应该是套个线段树进行维护的。不过,那个我并不会。所以这里写的是“树链”,真实面目其实应该是某种启发式合并。

首先,定义结点的 size 值为以该结点为根的子树的结点数。
给定一棵有根树,对于每个非叶子结点 u,设 u 的子树中 size 最大的子树的树根为 v,则标记 (u,v) 为重边,u 向其他儿子的边均为轻边,如下图所示。

根据上面的定义,只需一次 DFS 就能把一棵有根树分解成若干重路径(重边组成的路径)和若干轻边。

路径剖分有两条重要定理:

  1. 对于 u 的子结点 v,当 (u,v) 为轻边时,size(v)<size(u)÷2
    理由:根据定义,所有非叶结点往下都有一条重边。不妨假设 size(v)size(u)÷2,则对于 u 向下的重边 (u,v) 来说,size(v)size(v)size(u)÷2,可得 size(u)1+size(v)+size(v)size(u)+1,与假设矛盾。
  2. 由定理 1 得,对于任意非根结点 u,在 u 到根的路径上,轻边和重路径的条数均不超过 log2n,因为每碰到一条轻边,size 值就会减半。

这样,在处理一类统计子树相关问题时,可以采用如下策略:

  • 从所有叶子结点出发向上考察
  • 每当到达一个结点时,要计算其各子树对当前总子树的答案贡献。对于重儿子(以重边连接的儿子),直接将其答案累加。对于轻儿子,dfs暴力统计。

对于重儿子,显然计算效率会比较高。但轻儿子的暴力统计呢?这样会不会导致超时?

其实是不会的。根据定理 2 可知,每个结点到根结点的路径上最多不会存在超过 log2n 条轻边,即,每个结点最多被统计 log2n 次。这样,总的时间复杂度其实只有 O(nlog2n)。而对于真正的套上线段树的树链剖分,由于线段树的操作也是 log 级别的,因此复杂度还要再套一个 log,为 O(nloglogn)

直接这样讲会感觉很抽象,所以还是要通过例题来说明。详见《树》解题报告。