chang-pou
长剖
一般是优化 dp 用的。
比如说,求每个点子树内,某个深度的所有点的某些信息。(\(max, min, sum\) 等等)
假设现在要求,对每个点求子树内距离它为 \(k\) 的所有点点权和。\(k\) 不定。
可以考虑一个 \(n^2\) dp,设 \(f_{u,i}\) 表示 \(u\) 子树内距离 \(u\) 为 \(i\) 的所有点点权和。
转移就是,\(f_{u,0}=a_u\),剩下的 \(f_{u,i}=\sum_vf_{v,i-1}\)。
我们注意到,假设 \(mx_u\) 表示 \(u\) 子树内到 \(u\) 距离最大的点的距离,\(sec_u\) 表示 \(u\) 子树内到 \(u\) 距离次大的点的距离。
则发现 \(f_{u,(sec_u,mx_u]}\) 算的点都是唯一的,就是长链上末端的点。
设 \(son_u\) 表示 \(u\) 的重儿子(或者叫长儿子),那么我们可以这样 dp:
dp 到 \(u\) 的时候,从 \(f_{son_u}\) 部分直接继承信息,对每个剩下的儿子 \(v\) 枚举 \(v\) 所有的深度,即 \(mx_v\),暴力转移。
一种写法是,对每个 \(f\) 开一个反过来的 vector \(f'\),\(f'_{u,i}\) 存原来的 \(f_{u,mx_u-i}\)。
这样可以直接从儿子继承,即 \(f'_{u}\) 先等于 \(f'_{son_u}\),其他儿子再暴力转移。
这样很不好写!有一个非常好写法,爱来自cyf:
dp 到 \(u\) 的时候,把 \(f_{u,i}\) 存在 \(u\) 所属长链的 \(u\) 向下走 \(i\) 格的点上。
这个很牛,这样从重儿子继承就啥都不用改。轻儿子暴力转移的话,就枚举一个轻儿子 \(v\),从 \(u,v\) 的长链同时开始走,走到的 \(u',v'\) 令 \(f_{u'}\gets f_{u'}+f_{v'}\) 即可。
然后复杂度还没证,我们会发现这样每次暴力转移,每个轻儿子 \(v\) 会产生 \(mx_v\) 的贡献。
这些轻儿子一定都是长链链顶。所以等于说每条长链都会在链顶的父亲处被计算长度次。
而所有长链长度之和是 \(n\)。所以复杂度 \(\Theta(n)\)。
看一个题:link
考虑枚举路径的 \(lca\) 为 \(t\)。现在如果只有这一个点,答案是 \(g_t\),\(g_t\) 为所有点到 \(u\) 的距离之和。
如果路径某一端 \(u\) 拓展了一个点 \(v\),那么答案会变小 \(w(u,v)\times siz_v\)。假设选了 lca 子树内两点 \(u,v\) 作为路径端点,那么答案就是 \(g_{t}-\sum_{i:t\to u}w(i,fa_i)\times siz_i-\sum_{i:t\to v}w(i,fa_i)\times siz_i\)。
设 \(s_u=\sum_{1\to u}w(i,fa_i)\times siz_i\)。则上式就是 \(g_t-(s_u-s_t)-(s_v-s_t)\)。
也就是说,要在子树 \(t\) 内选两个不同子树的点 \(u,v\),满足到 \(t\) 距离之和为 \(k-1\),且 \(s_u+s_v\) 最大。
考虑 dp,设 \(dp_{u,i}\) 表示 \(u\) 子树内距离 \(u\) 为 \(i\) 的点的点权最大值。
那么枚举其中一个的深度 \(i\),另外一个就是 \(k-1-i\),两个最大值相加即可。
注意到有来自不同子树的条件(即两条路径不相交)。那么可以将儿子 \(v\) 的信息合并进去前算一下 \(v\) 的所有深度的贡献,即在之前已经转移好的 dp 数组里求一下 \(k-1-i\) 深度的最大值。
长剖优化一下,转移还是合并轻儿子前算一下贡献。注意考虑 \(u,v\) 中一个等于 \(t\) 的情况。
复杂度 \(\Theta(n)\)。

浙公网安备 33010602011771号