區間反轉問題
本篇隨筆淺談一下算法競賽中的區間反轉問題。
例題 洛谷 P3391 【模板】文藝平衡樹
題目描述
您需要寫一種數據結構(可參考題目標題),來維護一個有序數列。
其中需要提供以下操作:翻轉一個區間,例如原有序序列是 5\ 4\ 3\ 2\ 15 4 3 2 1,翻轉區間是 [2,4][2,4] 的話,結果是 5\ 2\ 3\ 4\ 15 2 3 4 1。
輸入格式
第一行兩個正整數 n,mn,m,表示序列長度與操作個數。序列中第 ii 項初始為 ii。
接下來 mm 行,每行兩個正整數 l,rl,r,表示翻轉的區間。
輸出格式
輸出一行 nn 個正整數,表示原始序列經過 mm 次變換后的結果。
說明/提示
【數據范圍】
對於 100%100% 的數據,1 \le n, m \leq 1000001≤n,m≤100000,1 \le l \le r \le n1≤l≤r≤n。
關於區間反轉
對於反轉一段區間的操作,我們好像怎么搞都是\(O(N)\)的。
然而對於這道題來講,\(O(N)\)算法肯定是過不去的。
想要用更優秀的復雜度來做,怎么辦呢?
用平衡樹來升級,而且必須用Splay。
復雜度達到了均攤\(O(\log N)\)(證明別找我)。
這就已經很優秀了。
那么為什么平衡樹的Splay算法能夠用均攤\(O(\log N)\)的復雜度來實現區間反轉呢?
現在我們用節點編號來建一棵BST。那么根據BST的性質,對於一個針對區間\([L,R]\)的反轉操作,我們肯定需要把這個區間變到一個可以方便操作的位置。
那么我們考慮把節點\(L-1\)用旋轉splay到根節點,把節點\(R+1\)用旋轉splay到根節點的右兒子,根據BST性質,因為我們是使用節點編號建的BST,那么我們就發現:右兒子的左子樹就是我們需要操作的區間。這個區間已經被唯一確定下來了。
然后因為我們是用節點編號建的BST,所以直接把每個節點的左右兒子交換就可以。
