虚树入门

虚树入门

标签: 虚树


概念

在处理某些问题时,不需要用到整棵树的信息,只需要某些点时,我们可以新建一棵虚树来放这些点与某些关键点。通常来说,构建的虚树中有这些点和这些点的lca。假如我们要将k个点与其lca构成一棵虚树,那么所需要的时间复杂度为O(klogk)。

顺便提一下,这k个点和其所有的lca的点的个数和是小于2×k-1的,至于为什么的话,可以看构树的过程,每加入一个点最多只会多一个点。

构建过程

我们先对原树dfs一遍,得到原树的dfs序。
然后我们把需要加入的点按照dfs序排序,这有什么好处呢,下文会提到。
我们还需要维护一个栈,这个栈中存的是最后一个新加入的点的dfs链。(在这条链上,dfs序是递增的)
现在新插入一个点v,假如栈顶的元素为u,现在有两种情况:

  1. lca(u,v)==u:
    • 我们就可以直接把v插入栈中,继续维护这条链;
  2. lca(u,v)!=u:
    • 首先lca(u,v)不可能等于v吧。(因为我们是按照dfs序依次加入的,这点很重要!)
    • 其次,再也没有新的点会插入在u的子树内了(因为我们是按照dfs序依次加入的,这点很重要!)。
    • 所以这一条链已经没有多大维护的价值了,我们把这一条链加入到虚树中,具体怎么做呢?
    • 假如栈顶为p,栈中的第二个元素为q。
    • 当dfn[q]>dfn[Lca]这时q还在Lca子树内,q->p连边,弹出栈顶。
    • 当dfn[q]==dfn[Lca]这时q为Lca,q->p连边。
    • 当dfn[q]< dfn[Lca]这时元素q还有维护的价值(可以q->Lca->v构成一个新的链),Lca->p连边,弹出栈顶,Lca加入栈。
    • 最后插入v。

等点全部加完后,记得把栈中的所有点加到虚树里去。(这是初学者容易犯的错误)
这样一棵虚树就建好了。


推荐几道模板题:
[Sdoi 2011]消耗战
[Heio 2014]大工程

原文地址:https://www.cnblogs.com/gzy-cjoier/p/7622928.html