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\),使得樹上任意點父親的位置在這個點前面。
然後要使得以下值最小化:
然後這一題容易發現,還是和上一題類似,要讓 \(a\) 序列的順序對數儘量小即可(接近降序排序)。
這裡有兩種思路,但是最後程式碼寫法是一樣的。
考慮算貢獻:
對於某個點的一對兒子 \((x,y)\),如果先合併 \(x\) 優於先合併 \(y\),那麼就有:
於是並查集維護權值和、大小即可貪心。
考慮轉換為上一題
對於 \(a_i\) 這個權值,倒過來排序,直接將 \(a_i\) 視為 \((0,0\dots 0,1)\),其中有 \(a_i\) 個 \(0\),然後變成第一道題目。
那麼 \(0\) 正好就是權值和,\(1\) 就是大小,按照 \(\frac{c_1}{c_0}\) 排序即可。
最後算答案就是這麼合併即可:
時間複雜度:\(O(n\log n)\)。
程式碼