虚树

虚树用于将一棵树的无意义点删除, 只保留关键点和树的结构, 优化树形dp的速度。

构建虚树

初始化一个栈, 将根节点入栈(必须保留根节点以供遍历), 然后根据(dfn)序遍历这颗树。

遍历途中把关键点依次入栈, 当要添加一个新的关键点((v))时, 求(v)与栈顶((stk[top]))的(lca(v, stk[top])),此时有几种情况:

  1. (lca(v, stk[top]) = stk[top]) ,直接入栈。

  1. (lca(v, stk[top]) != stk[top])

此时(stk[top])所在子树必定已经处理完毕, 所以可以开始构建虚树。

(stk[top])(stk[top - 1])连边, 然后将(stk[top])出栈, 接下来原来的(stk[top - 1])变成(stk[top]), 然后如此循环, 直到(stk[top-1])深度小于等于(lca(v, stk[top]))

如果(lca(v, stk[top]))在栈内即(stk[top-1])深度等于(lca(v, stk[top])),将(stk[top])(lca(v, stk[top]))连边, (stk[top])出栈即可。

如果(lca(v, stk[top]))不在栈内即(stk[top-1])深度小于(lca(v, stk[top]))

图中 lca 指 lca(v, stk[top])

因为此时需要保留树的结构, 所以将(stk[top])(lca(v, stk[top]))连边, (stk[top])出栈,(lca(v, stk[top]))入栈, 向(v)方向继续遍历。

处理完成后的情况

此时左子树已经完全出栈, 栈内只存在一条链。

遍历完之后, 栈内也只存在一条链, 依次退栈, 也要把(stk[top])(stk[top-1])连边。

原文地址:https://www.cnblogs.com/youxam/p/virtual-tree.html