給定長度 n(≤ 10⁵)的序列,m(≤ 5000)次查詢:區間 [l, r] 中第 k 大的數。無修改操作。
將原數組值與下標配對排序。每次查詢按值從大到小掃描,計數下標在 [l, r] 的元素,第 k 個即為答案。
雖然理論複雜度高,但 m ≤ 5000,配合 O2 優化常能通過。
線段樹每個節點存儲該區間已排序的數組。建樹時歸並合併子節點數組。
查詢:二分答案值域,利用 lower_bound 在 log n 層節點上計數 ≤ mid 的個數,總查詢 log³ n。
代碼關鍵:
build 遞歸歸並排序
query(v, L, R) 返回區間 ≤ v 的個數
solve(l, r, k) 二分值域找第 k 大
主席樹(可持久化線段樹)是標準最優解。每個前綴建一棵線段樹,查詢兩棵樹相減得到區間頻率,直接二分樹上找第 k 大。
分塊樹(劃分樹)同樣 O(log n) 查詢,實現較複雜。
本題數據範圍下,歸並樹足夠,主席樹代碼較長此處略過。
| 方法 | 預處理 | 單次查詢 | 備註 |
|---|---|---|---|
| 離線枚舉 | O(n log n) | O(n) | 代碼最短,實測常通過 |
| 歸並樹 | O(n log n) | O(log³ n) | 平衡選擇 |
| 主席樹 | O(n log n) | O(log n) | 理論最優,代碼長 |