前言
有一类问题,形如:给出一棵n个点的树,每次给出k个关键点,求这些关键点之间的一些信息。
保证∑k和n同阶
而对于一次询问是很好用树形Dp之类的方法解决的。
观察到只有关键点有用,我们可以只保留关键点和两两之间的lca,这就是虚树。
显然虚树的大小是O(k)的,只有dfs序相邻的两个点的lca有用
建出虚树后这类问题我们只需要在虚树上Dp就可以了。
但虚树要怎么建立?
单调栈
我们先把所有点按dfs序排序,按深度维护一个单调栈,表示从栈顶所代表点到根的一条链
接下来我们插入点x,设栈顶为p,我们求出lca=lca(p,x),接下来有两种情况
lca=p,那么我们直接将x入栈
lca!=p,那么我们接着考虑,设栈顶的上一个点为q,又分两种情况
dfn[lca]<=dfn[q],说明p的子树都已经构建完了,我们直接将q->p连边,然后弹栈
dfn[lca]>dfn[q],说明lca夹在q和p中间,那么我们连lca->p,然后弹栈
接着我们判断栈顶是不是lca,不是就把lca入栈,然后再把x入栈
这样子画一画图就可以理解了。
最后我们再把这一条链给连起来就好了。