虚树浅谈
我们就直接进入主题了,毕竟还有 $1 \tt h$ 就要准备去考场了,可能是我退役前的最后一篇学术类的吧。
树上的题目中可能会给出 $\sum k_i \le 5 \times 10^5$ 之类的限制,那么我们常常会考虑到两种东西:
自然根号,也就是本质不同的 $k_i$ 只有 $\sqrt V$ 种。
虚树。
对于给定的一个点集,我们往往不希望这个是一个森林,所以我们钦定加上根节点特判即可。
我们考虑将点集按照 $\tt dfs$ 序进行排序,之后从前向后往栈中加点。我们设 $lc$ 表示当前点和最后加入栈的点的 $\tt Lca$。
如果 $lc = stack(ed)$ 那么意味着还是同样一个子树的链,我们直接加入即可。
不然意味着更换了子树,我们考虑将当前子树的树全部建出,那么因为更换了子树,也就是意味着 $dfn_{lc} \le stack(ed)$ 的,我们考虑退栈直到合法为止。
1
while(ed > 1 && dfn[lc] <= dfn[st[ed - 1]]) G.add(st[ed - 1], st[ed]), -- ed;
我们栈中还有最后一个点没有退栈,那么意味着
st[ed - 1]
已经是lc
的祖先了,而且dfn[lc] <= dfn[st[ed]]
也就是意味着要么两者相同,要么lc
是st[ed]
的祖先,加边即可。之后再加上当前的节点。
具体来说实现是这样的:
1 | st[ed = 1] = 1; |
其实还有一种建树的方法,我们考虑建立欧拉序设点 $p$,进入和出去的标号分别是 dfin[p], dfot[p]
。
我们可以将需要的 $\tt Lca$ 拿出来,之后复制一份作为 dfot[p]
然后排序,用栈来维护即可。来自 shadowice1984
的题解。
1 | int cmp(const int &a, const int &b) { |
例题:
要相信 $\tt sort$ 的速度。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Legendgod's Blog!
评论