contents
Problem
背景
史蒂芙被王國政務工作忙昏頭,每次都要求效率的極限,即使不會玩遊戲,只要把政務工作處理到極致,想必這就是另一種人生價值。
題目描述
回顧一個經典問題區間極大極小值詢問 RMQ,她收到下面這一份代碼
|
|
「給定 $N$ 個整數、$M$ 個詢問操作、$S$ 為亂數種子,接著產生 $N$ 個數字,對於接下來 $M$ 個詢問,每一個詢問兩個整數,輸出區間內的最大值。」這對曾經的史蒂芙而言,用過 Segment Tree、Sparse Table、Unrolled Linked List 解決過,時間、空間複雜度都非常優秀。
現在的工作就是加速這一份代碼。
Sample Input
|
|
Sample Output
|
|
Solution
經典 RMQ 問題,主要有以下四種,最後一種只支持離線不帶修改的操作。
- sqrt-decomposition $O(N)$ - $O(\sqrt{N})$
- sparse table $O(N \log N)$ - $O(1)$
- segment tree $O(N)$ - $O(\log N)$
- cartesian tree + tarjan LCA algorithm + morris traversal $O(N + Q)$
於是出了這一題 b494. 史蒂芙的修羅道,把第一種算法卡時間、第二種算法卡空間、第三種算法卡常數。
實作起來非常變態,速度一不小心就會輸非遞迴的 segment tree (zkw 線段樹或者稱做 non-recursive segment tree 的實作技巧,詳見 codeforce - Efficient and easy segment trees ),儘管如此還是卡不住這類的實作,但時間上把遞迴實作的版本卡 TLE,速度略贏 prefect tree 的 segment tree 的實作,但使用空間多了兩倍。
- 不開
std::vector
,否則記憶體會預保留一倍。 - 使用 tarjan LCA algorithm 在笛卡爾樹二元樹上時要特化操作。
- 無法使用遞迴,實作非遞迴的二元搜尋樹走訪常數要注意。
通常 tarjan LCA algorithm 會把一個詢問拆成兩個詢問,常數會多 1。在笛卡爾樹上有一個性質,每一個節點的狀態為 <key, value>
看 key 仍然是一個二元搜尋樹,看 value 是一個 heap,在完成 tarjan LCA algorithm 需要的是後序走訪,能保證回答 LCA(x, y)
的順序。假設詢問 LCA(x, y) && x < y
只需要在 y 節點準備詢問 x 即可。
若要降空間複雜度常數,利用 morris traversal 在空間複雜度 $O(1)$ 完成。若使用 stack<>
模擬 tarjan LCA algorithm,最慘的空間複雜度是 $O(N)$。
morris traversal
|
|
stack
|
|