權值樹狀數組就是數組下標是數值的數組,數組存儲下標對應的值有幾個數數組
幾種操做,p=0表明push:將數值爲a的數壓入盒子spa
p=1表明pop,表明刪除數值爲e的數,若是沒有這個數,輸出No Elment!code
p=2表明query,查詢比第k個比a大的元素,找不到輸出Not Find!input
5 0 5 1 2 0 6 2 3 2 2 8 1 7 0 2 0 2 0 4 2 1 1 2 1 2 2 1 3 2 1 4
No Elment! 6 Not Find! 2 2 4 Not Find!
此題正是權值樹狀數組的應用,插入和刪除都比較簡單再也不贅述了,重點是查詢怎麼查詢,咱們的樹狀數組是存儲的對應權值的個數。咱們在查詢的時候,首先查詢出a是第\(x\)大的元素,那麼查詢比a大k的元素就轉化爲查詢第\(x+k\)大的元素,而後咱們二分查找,判斷當前的數是第幾大的數,多了就向小二分,但要注意判斷,若是當前找到的是第\(res\)大的數,vis[mid]表明這個數有多少個,若是\(res-vis[mid] < k 且res >= k\)說明mid就是要找的數string
#include <cstdio> #include <cstring> #include <algorithm> #define N 100005 using namespace std; typedef long long ll; int lowbit(int x) { return x & (-x); } int min(int a, int b) {return a < b ? a : b; } int max(int a, int b) {return a > b ? a : b; } int m; int d[N + 5]; void update(int x, int val) { for (; x <= N; x += lowbit(x)) d[x] += val; } int query(int x) { int ans = 0; for (; x; x -= lowbit(x)) ans += d[x]; return ans; } int vis[N]; int main() { while (scanf("%d", &m) != EOF) { memset(d, 0, sizeof(d)); memset(vis, 0, sizeof(vis)); for (int i = 1; i <= m; i++) { int p, x; scanf("%d", &p); if (p == 0) { scanf("%d", &x); vis[x]++; update(x, 1); } else if (p == 1) { scanf("%d", &x); if (vis[x]) { update(x, -1); vis[x]--; } else printf("No Elment!\n"); } else { int a, k; scanf("%d%d", &a, &k); int l = 1, r = N; int ans; if (query(r) - query(a) < k) printf("Not Find!\n"); else { int x = query(a) + k; while (l <= r) { int mid = (l + r) >> 1; int res = query(mid); if (res >= x) { if (vis[mid] == 0) r = mid - 1; else if (res - vis[mid] < x) { ans = mid; break; } else r = mid - 1; } else l = mid + 1; } printf("%d\n", ans); } } } } return 0; }