初学虚树

我怕爱的太早我们不能终老 提交于 2019-12-02 09:13:25

今天考了个模拟赛,虚树的题我拿\(LCT\)粗暴卡过,然后被各路神仙疯狂嘲讽,然后就奋发图强,来学了个虚树。

虚树的概念

先放一个例题吧:[SDOI 2011]消耗战

例题单个询问的树形DP可以说是非常简单了,但是多个询问就会\(GG\),于是我们痛定思痛,发现其实我们并不需要整棵树来转移,我们只需要得到每一个目标节点和他们的\(LCA\)所构成的树即可,而树的边权即为树上两点在原树上的路径中的最小值。

那么像这种由目标节点和他们的\(LCA\)所构成的树即为虚树。

虚树的构造

既然知道了啥是虚树,那么就让我们再来看看虚树应该怎么构造吧。

其实虚树的构造过程类似\(dfs\)

我们先整个类似\(dfs\)的栈,这个栈里存的只有虚树上需要的节点。

那么对于一个新加入的目标节点 \(x\)(显然目标节点要按\(dfs\)序排序再加入),我们分两种情况讨论:

  • \(x\) 在以\(stk[top]\)为根的子树中

  • \(x\) 不在以\(stk[top]\)为根的子树中

第一种情况很简单,直接把 \(x\) 加入栈即可。

让我们来具体研究一下第二种情况:

我们找到次栈顶结点\((stak[top-1])\)\(x\)\(LCA\) ,我们只需要一直把次栈顶与\(LCA\)比较,若 \(dep[stk[top-1]]>dep[LCA]\) ,那么便将给栈顶\((stk[top])\)和次栈顶\((stk[top-1])\)之间连一条边。

如果某一时刻\(dep[stk[top-1]]<dep[LCA]\&\&dep[stk[top]]==dep[LCA]\),那么就说明\(LCA\)就是\(stk[top]\),我们只需要连上\((stk[top],x)\)这条边即可。

那么如果\(dep[stk[top]]>dep[LCA]\)呢?

这就说明\(LCA\)并不在虚树中,我们需要连上\((stk[top],LCA)\),然后将\(LCA\)\(x\) 加入栈中。

最后,给出建虚树代码:

void ins(int x){
    int l=lca(x,stk[top],0);
    while (top>1&&dep[l]<dep[stk[top-1]]){
        E[stk[top]].push_back(stk[top-1]);
        E[stk[top-1]].push_back(stk[top]);
        --top;
    }
    if (dep[stk[top]]>dep[l]){
        E[stk[top]].push_back(l);
        E[l].push_back(stk[top]);
        --top;
    }
    if (stk[top]!=l) stk[++top]=l;
    stk[++top]=x;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!