當咱們得到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了。
總之,這個過程看似複雜,但只要想着要始終維護棧的性質(從棧底到棧頂的元素構成虛樹中從上到下的一條鏈)就不容易打錯了。寫的時候能夠畫個圖,讓本身思路清晰