当咱们得到k个关键点后排序
首先把关键点按dfn(即原树的dfs序)从小到大排序top
而后开一个栈block
栈的意义(性质):从栈底到栈顶的元素构成(表示)虚树中从上到下的一条链枚举
虚树构建过程:return
依次枚举关键点x
当栈为空或栈中只有一个元素(即top<=1,top从0开始),直接把x压入栈中(break/return)
不然令lca=LCA(x,stk[top])
若是lca=stk[top]
说明x应该接在stk[top]的下面(在虚树中),因此直接把x压入栈中(break/return)
若是lca!=stk[top]
说明x和stk[top]分属lca的两棵不一样的子树,并且stk[top]所在的子树中已经构建完成了,因此咱们把lca的stk[top]所在的那棵子树弹栈,在弹栈的过程当中建边(单向边),直到 dfn[stk[top]]<=dfn[lca]<=dfn[stk[top-1]] (即lca在栈顶的两元素的路径上) 或 栈中元素小于2的时候中止弹栈,并判断lca是否等于stk[top]
若不等,先从lca向stk[top]连边,压入lca,再压入x
不然直接压入x
枚举关键点结束后,若栈中的元素超过2个(即top>1),就不断从stk[top-1]向stk[top]连边,并弹出栈顶。
到此,虚树构建完成,而后就能够愉快地DP了。
总之,这个过程看似复杂,但只要想着要始终维护栈的性质(从栈底到栈顶的元素构成虚树中从上到下的一条链)就不容易打错了。写的时候能够画个图,让本身思路清晰