CodeForces - 1354D Multiset(樹狀陣列倍增找第k大)
阿新 • • 發佈:2021-08-17
題目大意
模擬一下multiset,一共有兩個操作:
1.插入一個數
2.刪除第k小的數
解題思路
用權值樹狀陣列來維護,主要是新學了樹狀陣列倍增的方法,可以比二分少一個log來查詢第k小的數,需要maxn是2的冪。
比如要查詢第k小的數,我們倒著列舉二進位制位,如果區間\([0, 2^x]\)的數的數量比k要小,那麼說明第k小的數肯定是比\(2^x\)要大的,那麼根據二進位制的性質,這個數肯定是介於\([2^x, 2^{x+1}]\)之間的,那麼我們就用一個變數res加上\(2^x\),然後k減去其中的數量。再繼續列舉更低位,判斷區間\([res, res+2^y]\)
const int maxn = 1<<20; const int maxm = 2e5+10; int n, q, c[maxn+1]; void add(int x, int y) { while(x<maxn) { c[x] += y; x += x&-x; } } int get_k(int x) { int res = 0; for (int i = maxn/2; i>=1; i>>=1) if (c[res+i]<x) { res += i; x -= c[res]; } return res+1; } int main(void) { IOS; cin >> n >> q; for (int i = 1; i<=n; ++i) { int num; cin >> num; add(num, 1); } while(q--) { int num; cin >> num; if (num>0) add(num, 1); else { num = -num; int x = get_k(num); add(x, -1); } } int ans = 0; for (int i = 1; i<maxn; ++i) if (c[i]) { ans = i; break; } cout << ans << endl; return 0; }