【题解】P5024 [NOIP2018 提高组] 保卫王国 虚树、树形DP、倍增、子树合并

题目链接

*\(T(u)\) 表示以 \(u\) 为根的子树,定义一对祖先与后代的 \(pre(u,v)\) 为 路径 \(u\to v\) 经过的第二个点。

对于一个询问 \((x,y,a,b),a,b\in\{0,1\}\) ,其中 \(dep(x) \ge dep(y)\) 考虑将树 \(T\) 拆成若干个部分:\(T(x),T(y),T-(T(x)\bigcup T(y))\)

对于前面两部分的维护比较平凡,考虑如何维护 \(T-(T(x)\bigcup T(y))\) 的答案。

\(LCA(x,y)\not =x\) ,那么 \(T-(T(x)\bigcup T(y)) = T - T(x) - T(y)\) ,即 \(x\)\(y\) 的子树补。

考虑处理子树补。

我们发现我们可以很容易的处理一个点的子树补的答案:即形如 \(T-T(u)\) 的答案。

我们考虑维护出每个子树的子树补和每对祖先与后代的 “子树的子树补” 的答案。

具体地:我们将 \(T - T(x) - T(y)\) 拆成 \(T - T(LCA(x,y)) + T(LCA(x,y)) - T(x) - T(y)\)

而对于 \(T - T(LCA(x,y))\) 则是其 \(LCA\) 的子树补,而对于 \(T(LCA(x,y)) - T(x) - T(y)\) ,同时维护两个点的子树补我们发现复杂度十分巨大,但是我们可以通过类似 “合并子树” 的操作,合并 \(pre(LCA(x,y),x),pre(LCA(x,y),y)\) 的 “子树的子树补” 来维护出两个子树的子树补。

具体地,我们维护出 \(gh[i][j][0/1][0/1]\) 为点 \(i\) 选 / 不选 \(j\) 选 / 不选覆盖 \(T(j) - T(i)\) 的最小代价,其中 \(j\)\(i\) 的祖先。

而对于 \(LCA(x,y) =x\) 的情况,我们可以将其拆成: \([T(x) - T(y)] + [T - T(x)] + [T(y)]\) ,维护方法也类似。

而对于树上祖先与后代的关系,我们可以考虑通过树上倍增维护虚树上的信息。

即:本质上我们维护的东西是 “从一个点往上按照通用规则 DP 到另一个点的结果”。

考虑令 \(gh[i][j][0/1][0/1]\)\(i\) 选 / 不选 \(anc\) 选 / 不选覆盖 \(T(anc) - T(i)\) 的最小代价,其中 \(anc\) 是点 \(i\)\(2^j\) 级祖先。

这样总的复杂度为 \(O(n\log n)\)

代码记录

posted @ 2021-09-06 12:50  Themaxmaxmax  阅读(61)  评论(0编辑  收藏  举报