1. 程式人生 > >FZSZ 2018.9.8.?校聯考

FZSZ 2018.9.8.?校聯考

關於第2題的想法:

因為一定要保含某個標記(節點),所以可以從這個點為根節點出發找最長鏈。但是這樣,由於詢問(求某個標記為根的最長鏈長度)比較多,如果用普通求最長鏈的話,還要每次都DFS一遍,這樣是非常不划算的,因為這樣重複獲得了一些已經獲得的結果。

於是我加一個優化:假設這條最長鏈一定會經過樹根(原來的),那麼它的最長鏈就一定是從它往下找最長和次長,再往上找最長,結果就是把往下的次長與往上的最長取max然後加上往下的最長。 然後這樣就可以把第一遍DFS記下的fromroot[]和dpth[]更好的利用。那麼我現在去掉最長鏈一定經過原來的根節點這個假設,那麼對於每個樹的內部節點,從它開始的最長鏈(不考慮從詢問目標到它)一定是在與它相連的剩下的鏈中,即若DFS查詢的話需要在往它的父親和其他孩子(除了到這個點時經過的)走然後繼續查詢。那我要知道的就只是從Target到Now的距離+從Now出發能找到的“最長鏈”,並對所有的取個max。所以我一定需要Now往它的“所有”孩子的走法能得到的最長鏈長度,這樣就只需要往原樹根走了。至於為什麼不用記下往父親走的最長鏈,在證明這個演算法的正確性的時候可以證明。因為假如到了原來的根節點,那麼已經獲得了關於它的所有鏈的長度,這在第一遍DFS返回的時候可以獲得,然後我處理一下,就需要記錄下除了第I個孩子開始的鏈的最長的從根節點開始的最長鏈的長度。但是這樣有個很嚴重的問題,空間可能不行。那麼我就可以不把這些值記錄在根節點上,而是分散到每個孩子上,這樣就不需要為每個節點開一個大小不一定適合的陣列或用比較慢的stl,也不需要動態記憶體了。這樣我對於每個節點,我需要記下的就不是2個量(最長,次長),而是3個!而這新的量可以在第1遍DFS時算出(離線真是個好東西)。 至於實現嘛,查詢的時候只需按照層返回到根就行了,這可能是logN級別時間複雜度。 另外,這樣的演算法可能還是會出現重複的情況。不過好在題目是沒有修改的,也不是強制線上的,我可以做完第一遍DFS後把所有的詢問排序一下,按照深度從小到大排序,然後對於排完的佇列從前往後正常查詢,得到的往上的最長鏈的值可以利用,減少重複(那我就把這個量記下),之後詢問的時候遇到這個節點可以直接利用。 還有,往下的最長鏈和次長鏈的長度可以在第一遍DFS的時候算出 備註:本人第一次用md,格式寫得很爛,請巨佬們飄過