09-03 題解
比賽地址
補題地址
這回打算改變一下方式, 從寫 "怎麼做題" 變成 "怎麼想題"
T1
什麼樣的兩個 \(a_i\) 能被合併到一個 Bug 上?
很簡單 (不過我也想了好一會), mod 2 同餘的兩個可以合併在一起
為了培養最強 Bug, 肯定不能往上疊負數, 所以上述內容針對序列中的所有正數
確定了選哪些數, 最少的操作步數是確定的, 這裡不再贅述
如果序列裡沒有正數怎麼辦?
顯然只能選一個最大(絕對值最小)的負數(或 0)
但是注意, 對於值相同的若干個下標 \(i\), 他們對應的最小步數可能是不同的 (? 我也不確定)
T2
如果沒有 "傳送門" 該怎麼做 ?
這就變成了簡單的數連通塊個數, 並查集維護維護
有 "傳送門" 呢 ?
這就相當於在連通塊之間連上了一些有向邊
根據上述思路, 把每個連通塊縮成一個點, 確定該點能到達哪些點 (代表著連通塊), 查詢時看看所有可達的連通塊中包不包括終點即可
但是賽時我沒有想這麼多, 用了原理類似但實現不太一樣的方法 : 該連通塊內有哪些傳送門, 這些傳送門又能到達哪些傳送門, 所有可達的傳送門的出口是否存在和終點在一個連通塊裡的
T3
翻轉一個區間對整個序列的逆序對數有什麼影響 ?
區間內部的 "順序對" "和逆序對" 互換, 區間外不受影響
怎麼利用這個資訊 ?
這一點我沒想到, 所以只打了 \(O(n^2 log\ n)\) 的暴力
序列長度是 2 的冪次, 很適合分治 (形成一棵滿二叉樹)
對於一個分治區間, 計算他的左半部分對右半部分貢獻的順序對和逆序對
- 如果翻轉在左半邊或右半邊內部, 那麼這部分貢獻不變, 向下遞迴
- 如果翻轉包含了這個區間, 那麼逆序對和順序對的個數交換
暴力做每次詢問是 \(O(n\ log\ n)\) 的, 怎麼最佳化 ?
每次翻轉的區間是等長的, 他們在分治樹上位於同一層
可以先找到包含 \(l_i\) 到 \(r_i\) 的所有塊的大區間, 在上面打個標記, 告訴他我在長度 (可用點的深度表示) 等於某某時進行一次翻轉
這就要求我們在每一個點上儲存他的子樹中深度為 \(x\) 的順序對和逆序對的和
幸好這樣做只會增加一個 log, 在 Push_up 時就可以處理出這部分資訊
Push_down 中有一些細節, 需要你 (我) 仔細思考一下