简介

长链剖分与轻重链剖分类似,只是将重儿子判定由子树大小变为子树深度,对于一些树上 \(\texttt{DP}\),例如 \(f_{u,i}=f_{v,i+1}\),通过指针令 \(f_v=f_u+1\),可以快速实现轻重儿子间状态转移。

​CF1009F​

Description

给定一棵 \(1\sim n\) 的树。设 \(d(u,x)\) 为 \(u\) 子树中到 \(u\) 距离为 \(x\) 的节点数。

对于每个点,求一个最小的 \(k\),使得 \(d(u,k)\) 最大。

Solution

设 \(f_{u,i}\) 表示 \(u\) 子树中到 \(u\) 距离为 \(i\) 的节点数。

用长链剖分维护,轻儿子暴力转移即可。

时间复杂度为 \(O(n)\)。

​Code​

​[POI2014]HOT-Hotels​

Description

给定一棵树 \(T\),在树上选 \(3\) 个点,要求两两距离相等,求方案数。

Solution

设 \(f_{u,i}\) 表示 \(u\) 子树中到 \(u\) 距离为 \(i\) 的节点数。

依次枚举 \((u,v)\),那么有三种情况:

  1. 有 \(2\) 个点枚举过,\(1\) 个点在 \(v\) 的子树内;
  2. 有 \(1\) 个点枚举过,\(2\) 个点在 \(v\) 的子树内。
  3. 两个点位于 \(u\) 的子树,第三个点为 \(u,v\) 的公共祖先。

设 \(g_{u,i}\) 表示到 \(lca\) 距离为 \(d\),\(lca\) 到 \(u\) 距离为 \(d-i\) 的两点的组合方案数。换而言之,即 \(g_{u,i}\) 表示还要再走 \(i\) 步才能匹配到第三个点的方案数。

那么 第一种对答案的贡献为 \(\sum_{i=0}^{dep_v}g^{'}_{u,i+1}f_{v,i}\),第二种对答案贡献为 \(\sum_{i=1}^{dep_v}f^{'}_{u,i-1}g_{v,i}\),第三种对答案贡献为 \(g_{u,0}\)。

\(f^{'}_{u,i}\) 表示被 \(v\) 更新前的 \(f_{u,i}\),\(g^{'}_{u,i}\) 同理。

最后答案为


\[\sum_{u=1}^n{\left(g_{u,0}+\sum_{(u,v)\in T}\sum_{i=0}^{dep_v}g^{'}_{u,i+1}f_{v,i}+f^{'}_{u,i-1}g_{v,i}\right)}\]


时间复杂度为 \(O(n)\)。

​Code​

​树上 k 级祖先​

Description

给定一棵 \(1\sim n\) 的树,有 \(q\) 次询问。

每次询问给出 \(x,k\),求 \(x\) 的 \(k\) 级祖先,强制在线。

Solution

  1. 倍增求出每个点的 \(2^i\) 级祖先;
  2. 将树长链剖分,求出每条链顶端向下 \(len\) 个点与向上 \(len\) 个点,\(len\) 为当前链的长度。

令 \(t=\operatorname{popcount}(k)\),那么有 \(2^t\le k<2^{t+1}\)。

询问时先跳到 \(x\) 的 \(2^{t}\) 级祖先,由于 \(2^t\le k<2^{t+1}\),那么 \(k-2^t<2^t\le len\),\(len\) 为 \(x\) 的 \(2^t\) 级祖先所在链的长度。可以直接 \(O(1)\) 查询答案。

时间复杂度为 \(O(n\log n+q)\)。

​Code​