做点简单 DP 陶冶情操。
考虑按以下方式行动必然不劣:
对于路径上每个点,以其为根,首先穿到不在路径上的点的子树中移动(并且这些边最多往返各经过一次),然后回到路径上走到下一个点。
考虑求出每个点为根时在各个子树内移动的最小代价,查询时减掉路径上的相邻点的贡献即可。
记其为 \(f_u\)。
不妨先计算 \(g_u\) 为任选一根时不考虑 \(u\) 的当前根向子树的答案。那么有显然转移 \[ \newcommand\fa{ \operatorname{fa} } \newcommand\lca{ \operatorname{lca} } \newcommand\child{ \operatorname{child} } \newcommand\path{ \operatorname{path} } g_u = a_u + \sum_{v\in\child(u)} \max\{0,g_v - z(u,v) - z(v,u)\} \]
对于 \(u\) 和 \(v\in\child(u)\),考虑按换根套路计算 \(f_v\),无非是 \(g_v+\max\{0, f_u-\max\{0,g_v-z(u,v)-z(v,u)\}-z(u,v)-z(v,u)\}\)。
对于询问 \((x,y)\),先计算路径上的边权和,然后剩下的部分就是 \[ \begin{aligned} &\quad\;f_{\lca(x,y)} + \sum_{ u\in\path(x,y)\setminus\{\lca(x,y)\} } (g_u-\max\{0,g_u-z(u,\fa(u))-z(\fa(u),u)\}) \\ &=f_{\lca(x,y)} + \sum_{ u\in\path(x,y)\setminus\{\lca(x,y)\} } \min\{g_u,z(u,\fa(u))+z(\fa(u),u)\} \end{aligned} \]
代码:
1 |
|