1. 程式人生 > >邊權最大差最小的生成樹

邊權最大差最小的生成樹

更新 第一次 然而 sort 還要 ima 右移 我們 一個

技術分享圖片

最小生成樹十分簡單,想求最大邊權最小的一個數。我們利用樹的性質和單調性,維護所有節點的父節點(剛開始的時候弄成自己)和一個當前用於建樹的邊數sum。先sort把所有邊按邊權從小到大排序,然後向後遍歷,如果這條邊的兩端點最大的父親不一樣就令他們合並,並且sum++。當sum==n-1時停下來,答案就是此時的邊權。

現在要求邊權最大差最小的生成樹,對小數據版就可以隨便搞:先跑一遍最小生成樹,如果停下來時sum!=n-1說明用所有的邊也無法使n個點在同一個樹上,輸出-1。如果等於了n-1,那麽此時的邊權減最小的邊權是一個可行解。再從小到大枚舉最小邊,以第i個邊為最小邊到達第f條邊sum==n-1停下來,更新答案,ans=min(ans,o[f].v-o[i].v);如果到最後也無法構造出樹就可以return 0了。

然而這是小數據,大數據肯定支持不了。

  我發現改變最小邊時中間無數的邊被拆下來又接回去,浪費了大量時間。

  於是就覺得可以維護一個數組bian[],跑第一次時把經過的每個邊的兩端點的bian[]++,最後sum=n-1時停下來,此時的bian[j]表示從第一條邊到第i條邊的邊權範圍中所有邊都連上的情況下j點所連邊的數量。

  也就是說,即使get(x)==get(y)也要把bian[x]++,bian[y]++;因為一會刪邊的時候可以直接判斷該端點要不要刪掉。

  然後左端點是1,右端點是i,先把左端點向左走,也就是最小邊向大的方向移動,並且把自己的兩端點bian[]--,有1個變為0時就sum--,兩個變為0還是sum--。一旦減了就不管左端點了,開始將右端點向右移動,還是把自己的端點bian[]++,如果發現了父節點不一樣的就連起來,sum++。知道sum==n-1,停下來,更新答案。

  然後再將左端點向右走,直到sum又被減了,再把右端點向右走,直到sum再加回去,更新答案,一直循環……

  直到直到右端點到達了m且sum!=n-1了的時候break。如果右端點到達m還要回去看看左端點能不能再向右走而且sum不被減。

  嗯也可以在左端點向右走而且sum不被減時更新答案,反正我寫了兩天也沒弄出來。

  交給你了,李澤鐸!打破通過一的慘案的光榮任務在你身上

邊權最大差最小的生成樹