一種型別的樹貪心

weirdoX發表於2024-10-22

AGC 023 F - 01 on Tree

從根開始往下順序不太好處理,於是考慮從下往上。

那麼就是從葉子開始,向自己的父親合併,我們對於一個點,它有若干個兒子,假設其中兩個葉子兒子分別為 \(x,y\),然後考慮誰先合併上來更優?顯然是顏色為 \(0\) 的先合併。

然後葉子合併完後每個點會變成連通快,我們擴充套件成連通塊 \(x,y\),記:\(c_{0/1,u}\) 表示 \(u\) 所在連通塊的 \(0/1\) 數量。

那麼如果先合併 \(x\) 就有:\(c_{1,x}\cdot c_{0,y}< c_{0,x}\cdot c_{1,y}\),移項就是:\(\frac{c_{1,y}}{c_{0,y}}<\frac{c_{1,x}}{c_{0,x}}\),那麼我們就將所有葉子插入一個優先佇列,然後選擇這個值最小的,向它的父親合併即可,用並查集維護 \(c_{0/1,x}\)。然後將父親插入佇列。

這題可以簡單點寫法,不需要先合併葉子(答案不影響,因為兒子遲早合併上來計算,且計算結果不變),將所有點都插入佇列,然後類似 dijkstra,因為一個點合併完之後某個點的父親點一定比值變小,所以用一個 bool 陣列記錄一下是否已經合併過了即可。

時間複雜度:\(O(n\log n)\)

程式碼

ABC 376 G - Treasure Hunting

確定一個排列 \(q\),使得樹上任意點父親的位置在這個點前面。

然後要使得以下值最小化:

\[\sum_{i=1}^n a_{q_i}\times i \]

然後這一題容易發現,還是和上一題類似,要讓 \(a\) 序列的順序對數儘量小即可(接近降序排序)。

這裡有兩種思路,但是最後程式碼寫法是一樣的。

考慮算貢獻:

對於某個點的一對兒子 \((x,y)\),如果先合併 \(x\) 優於先合併 \(y\),那麼就有:

\[sz_x\cdot sum_y < sz_y\cdot sum_x\\ \frac{sz_x}{sum_x}<\frac{sz_y}{sum_y} \]

於是並查集維護權值和、大小即可貪心。

考慮轉換為上一題

對於 \(a_i\) 這個權值,倒過來排序,直接將 \(a_i\) 視為 \((0,0\dots 0,1)\),其中有 \(a_i\)\(0\),然後變成第一道題目。

那麼 \(0\) 正好就是權值和,\(1\) 就是大小,按照 \(\frac{c_1}{c_0}\) 排序即可。

最後算答案就是這麼合併即可:

\[u\to v\\ ans_u = ans_u + ans_v + sz_v\cdot sum_u \]

時間複雜度:\(O(n\log n)\)

程式碼

相關文章