浅谈长链剖分

先放一个图,懂重链剖分的都懂。
长链剖分,顾名思义,就是对于子树深度的最大值对树进行剖分。
具体地,就是找到所有以儿子为根的子树中深度最大的点为重儿子,然后跑重边优先遍历即可。
接下来介绍她有什么性质。
性质与证明
-
一个节点 \(u\) 的 \(k\) 级祖先所在长链长度一定 \(\ge k\)
证明:我们考虑 \(x\rightarrow fa[x]\) 这条边
-
这条边是重边
那么 \(mxdep[fa[x]]=mxdep[x]+1\) .
-
这条边是轻边
那么 \(mxdep[fa[x]]> mxdep[x]+1\),不然的话这条边将是重边。
-
-
从根节点到任意节点经过的轻边条数不超过 \(\sqrt{n}\)
证明:我们从叶子节点开始考虑往上跳轻边(因为叶子节点一定是极端情况),设她的深度为 \(dep\),则子树大小至少增加 \(dep+1\) .
于是当我们走第一条轻边的时候,子树大小至少增加 \(1\) ,走第二条轻边的时候,子树大小至少增加 \(2\)(因为我们往上跳轻边时,当前点的所在的链长一定最长)……
然后我们发现跳 \(k\) 步时,我们最少子树大小为 \(\sum_{i=1}^k i=\frac{k*(k-1)}{2}=n\),所以 \(k\le \sqrt{n}\) .
-
长链剖分优化 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\) 级祖先。

浙公网安备 33010602011771号