1. 程式人生 > 其它 >做題筆記

做題筆記

為了監督自己做題時寫思路以集中注意力,從而提高效率,同時簡單記錄解法,防止以後看不懂自己程式碼特開此文。

只記錄簡單做法,為防止長度過長載入速度慢,所以就不貼程式碼了,反正到處都存了

CF1059E Split the Tree

簡單 2400 的題,做題時比較浮躁,靜不下來,做了比較久。

考慮到每個點必然包含在一條垂直路徑,根節點必然是垂直路徑的頂端。

定義 f[i] 表示以 i 號點為垂直路徑頂端點,i 的子樹內的節點全覆蓋的最少垂直路徑數量。

顯然滿足

\(\sum_{v \in son_x} f_v\) <= f_x <= \(\sum_{v \in son_x} f_v\) + 1 即要麼單飛,要麼與下面某條路徑合併

轉移即判斷能否找到一個單飛轉移點與當前點形成路徑滿足條件。

由此可知,單飛的越晚越優,即能不單飛就不單飛,既把單飛機會留給之後使轉移更多,又讓當前位置答案更小

由此發現,當答案最優時,單飛與否的狀態也是不劣的

明顯,當確定一個點單飛後,做一個差分維護是否單飛

可以倍增解決。

複雜度 \(O(n \log n)\)

[清北學堂] 校門外的樹

研究標程把這道題弄明白了,於是來寫一篇題解。

題意:

詢問一個區間內的元素的最小差值。

分析本題,發現能夠對答案產生貢獻的數對具有 \(n^2\) 個,但是其中存在大量的無用的數對狀態。

舉個例子,對於點 \(i,j\) ,滿足 \(h_i < h_j\)

,則發現滿足 \(k > j , h_j < h_k\)\(k\) ,都是無法與 \(i\) 對任何一個區間的答案產生貢獻的。因為他離 \(i\)\(j\) 遠,又沒有 \(j\) 貢獻答案優秀。

類似地,我們考慮能否進一步減少我們的有用的數對數量。

考慮 \(k>j , h_k < h_j\) ,發現這樣的一些 \(k\) 並不完全可能與 \(i\) 產生貢獻,因為這些數有可能與 \(j\) 組成數對會答案產生更優秀的貢獻。

簡單分析可以發現,當 \(h_k < (h_j + h_i) / 2\) 時,\(i,k\) 才不一定劣。

按照上述分析不斷迭代下去,容易發現,對於每個 \(i\)

,最只有 \(\log M\) 個(\(M\) 為值域) \(j\) 滿足 \(j > i\) 且與 \(i\) 組成數對不一定劣。

同理對 \(j > i , h_j < h_i\)\(j\) 尋找不一定劣的數對。

因此有用的數對個數就被壓縮到了 \(\log M\)\(M\) 為值域) 對。

考慮尋找這些數對。只用開一棵動態開點線段樹從後往前掃一遍,每次尋找滿足不一定劣值域範圍的最近的位置就好了。

找到數對後,離線詢問,左端點從大到小排序掃一遍,求符合範圍的數對權值最小值,用樹狀陣列維護一下就好了。