浅谈长链剖分

HLD

先放一个图,懂重链剖分的都懂。

长链剖分,顾名思义,就是对于子树深度的最大值对树进行剖分。

具体地,就是找到所有以儿子为根的子树中深度最大的点为重儿子,然后跑重边优先遍历即可。

接下来介绍她有什么性质。

性质与证明

  1. 一个节点 \(u\)\(k\) 级祖先所在长链长度一定 \(\ge k\)

    证明:我们考虑 \(x\rightarrow fa[x]\) 这条边

    • 这条边是重边

      那么 \(mxdep[fa[x]]=mxdep[x]+1\) .

    • 这条边是轻边

      那么 \(mxdep[fa[x]]> mxdep[x]+1\),不然的话这条边将是重边。

  2. 从根节点到任意节点经过的轻边条数不超过 \(\sqrt{n}\)

    证明:我们从叶子节点开始考虑往上跳轻边(因为叶子节点一定是极端情况),设她的深度为 \(dep\),则子树大小至少增加 \(dep+1\) .

    于是当我们走第一条轻边的时候,子树大小至少增加 \(1\) ,走第二条轻边的时候,子树大小至少增加 \(2\)(因为我们往上跳轻边时,当前点的所在的链长一定最长)……

    然后我们发现跳 \(k\) 步时,我们最少子树大小为 \(\sum_{i=1}^k i=\frac{k*(k-1)}{2}=n\),所以 \(k\le \sqrt{n}\) .

  3. 长链剖分优化 dp

    似乎会和 dsu on tree 一起用,而且 dp 应该有一维与深度有关!。就是说我们将重边直接继承,然后将轻边合并进去就行

    考虑证明这个东西复杂度 \(O(n)\) 正确性(因为我们通常是对于重链剖分中的重儿子来进行 dsu on tree ):

    就是说所以轻链长+根所在的长链长度 \(= n\) .

    而合并只和该点子树的最大深度有关。所以复杂度是 \(O(n)\) 的。

应用

求树上 \(k\) 级祖先

长链剖分可以帮你做到初始化 \(O(n\log n)\),查询 \(O(1)\) .

于是你可以类似倍增 lca 的思路求出 \(fa[x][i]\) 表示 \(x\) 往上跳 \(2^i\) 步的节点。

同时我们暴力的存下来每个链顶向上链长个节点,存下来每个链顶向下链长个节点(我们发现所有链长大小是 \(n\) ,所以这个vector存了 \(2n\) 个数,\(O(n)\) )。

然后查询的时候直接 \(O(1)\)\(t=\lfloor\log k\rfloor\) ,然后将 \(x\)\(2^t\) 步,然后根据性质1,所以我们要么向上要么向下总之一定能够找到 \(k\) 级祖先。

posted @ 2026-08-02 20:29  tyccyt  阅读(12)  评论(0)    收藏  举报