虚树
问题引入
在一类树上动态规划问题中,题目给出的询问往往包含树上的很多各节点,并保证总的点数规模小于某个值.
如果我们直接在整颗树上进行dpdp的话,时间复杂度与询问的次数有关,这显然是不可接受的,如果我们可以找到一种动态规划的方法,使其时间复杂度与询问中点的实际规模相关就好了.
于是虚树应运而生.
虚树概念
虚树即是一颗虚拟构建的一棵树,这个树只包含关键点以及关键lcalca的点,而其他不影响虚树结构的点和边都相当于进行了路径压缩,整颗虚树的规模不会超过关键点关键点数目的两倍.
举个栗子
原树
虚树
包含关键点 1 2 3的虚树
包含关键点 1 3 7 8 的虚树
其中6是关键lcalca节点
很显然,其他不是那么关键的点及边形成的路径我们都将他们压缩到了一条边,例如在第二个虚树中,我们相当于把1−61−6的路劲压缩到了边1−61−6中,而99号节点这种非关键点我们直接扔掉了,因为我们在 的时候不会用到99号点.
虚树构建
预处理我们对整颗树得到dfs序列(即前序遍历),记为 .
我们使用一个栈,从栈顶到栈底的元素形成虚树的一颗树链.
当我们得到一些询问点(关键点)的时候,对这些点按照他们的dfn[u]dfn[u]值进行排序,然后从dfndfn值小的开始扫描,结合栈中保存的树链信息就可以将这颗虚树构建出来.
假设我们当前扫到的关键点为