實時更新,遇到好玩的數據結構trick都會放到這里
\(1.\) 線段樹合並對於子樹查一類問題的應用:
由於子樹查問題的詢問之間往往具有信息包含關系,所以我們可以考慮將詢問離線下來,通過一次 \(dfs\) 將所有子樹的信息全部求出來,並在途中回答詢問。由於線段樹合並過程中線段樹代表的就是整個子樹內的內容,所以類似於子樹顏色眾數之類的問題也是可以解決的。
\(2.\) 區間某數出現次數的實現方式:
雖然主席樹可以做到在線 \(O(n \log_2 n) - O(\log_2 n)\),空間復雜度 \(O(n \log_2 n)\),但是查詢效率、預處理時間、空間沒有一項特別拔尖。我們可以考慮用 \(vector\) 記錄每一個數的所有出現位置,然后查詢時直接在對應的 \(vector\) 上二分即可,在線 \(O(n) - O(\log_2 n)\) 且空間復雜度 \(O(n)\)。考慮如何更快地回答查詢:我們用分塊預處理出 \(cnt_{i, j}\),前 \(i\) 塊中 \(j\) 的出現次數。這樣對於整塊,我們可以直接 \(O(1)\) 查詢,而對於散塊內部的個數,我們再次在 \(vector\) 上二分求出個數,這個算法在線,預處理 \(O(n \sqrt{n})\),空間 \(O(n \sqrt{n})\),但是時間變成了 \(O(\log_2{\sqrt{n}})\),近似於大常數 \(O(1)\)。
\(3.\) 分塊對於修改簡單,查詢復雜題目的應用:
如果修改只是單點修改,但是查詢比較非常規,可以考慮對於每一塊維護較為復雜的信息,然后單點修改時直接 \(O(\sqrt{n})\) 暴力重構塊。
\(4.\) 位運算:
維護位運算信息時,如果固定左端點,總共的 \(and, or, xor\) 等信息的可能種數只有 \(\log_2 V\) 種(\(V\) 代表值域)。此時我們就可以暴力二分出所有不同值的區間,進行信息的維護。
\(update:\) 其實 \(gcd\) 也只有 \(\log_2 V\) 種取值,因為 \(gcd\) 每次變小一定是除以一個至少為 \(2\) 的正整數。
\(5.\) \(st\) 表的應用:
所有滿足可以 \(pushup\),兩個相同信息作用后不變的信息都是可以用 \(st\) 表維護的。例如區間 \(gcd\),區間按位與,區間按位或等。
\(6.\) 第 \(k\) 小值:
第 \(k\) 小值可以通過一個 \(\log_2 V\) 的代價二分答案而轉化為區間小於 \(x\) 的值的個數,便於維護。
\(7.\) 字符串相關題目:
遇到字符串上區間修改區間查詢等問題時,可以考慮建字符集個線段樹來處理問題,一般會將問題簡化很多。而正解絕大多數情況下都是要依賴字符集大小的,不然這道題可以直接搬到序列上。
\(8.\) 線段樹合並的應用:
線段樹合並可以在過程中每一次合並后新開一個節點,這樣即使是強制在線也可以直接在查詢時在對應位置查詢,空間消耗也不是特別大。
\(9.\) 樹上問題:
當樹上問題只涉及對 \(x\) 子樹查詢的時候,換根是假的,因為新的根如果是 \(x\) 的祖先或者其祖先的其他子樹內的點,那么顯然子樹不變,如果是 \(x\) 那么顯然子樹是整棵樹,如果在 \(x\) 的子樹中那么子樹就是整棵樹刨掉一部分子樹,對應在 \(dfs\) 序上就是兩段區間。