作法一:兩個 multiset
以兩個動態排序的資料結構 \(L\) \(R\),分別維護前半小、後半大的,查詢時輸出中間切開的地方就行。 仔細地說,有奇數個元素時,中位數是 \(\lceil \frac n 2 \rceil\),偶數個時,中位數是 \(\frac n 2\)。 使 \(L\) 在 \(n\) 為奇數時,比 \(R\) 多一個,查詢時輸出 \(L\) 的最後一個元素。
這裏我踩到一個坑,就是 S.erase(x) 會把所有 x 刪除掉。 若只要刪除一個 x,使用 erase(S.lower_bound(x))
1 | int n, k, a[N]; |
作法二:在值域線段樹上二分搜
- 找到最小的 \(x\) 使 \(cnt[1]+ \dots +cnt[x] \le \lceil \frac n 2 \rceil\)
以 \(cnt[x]\) 代表目前 \(x\) 出現幾次。 當 \(n\) 為奇數,取 \(n/2+1\)。當 \(n\) 為偶數,取第 \(n/2\) 個,因此找到第一個包含 \(\lceil \frac n 2 \rceil\) 的 \(cnt[1]+ \dots + cnt[x]\)
- 在線段樹上二分搜:\(query(u,k)\) 所代表區間 \([l,r]\) 中,最左的 \(i\) 使得前綴至少為 \(k\)
1 | if (sum[l[u]] >= k) |
- 離散化
因為值域達 \(10^9\),並且只關心數字間大小關係,所以離散化。
1 | int n, k, a[N]; |
作法三:支援 find_by_order 的資料結構
可以自己刻一顆 treap,或是使用 pbds。
食用 pbds 前:
1 |
|
然後快樂的 AC 他:
1 | typedef tree< |