1. 程式人生 > >HDU 2852 KiKi's K-Number (樹狀數組 && 二分)

HDU 2852 KiKi's K-Number (樹狀數組 && 二分)

eof while ron name += oid names 如果 一個

題意:給出對容器的總操作次數n, 接下來是這n個操作。這裏對於一個容器提供三種操作, 分別是插入、刪除和查找。輸入0 e表示插入e、輸入1 e表示刪除e,若元素不存在輸出No Elment!、輸入2 e k表示查找比e大且第k大的數, 若不存在則輸出Not Find!

分析:這裏考慮樹狀數組做的原因是在第三個操作的時候, 只要我們記錄了元素的總數, 那通過求和操作, 便能夠高效地知道到底有多少個數比現在求和的這個數要大, 例如 tot - sum(3)就能知道整個集合裏面比3大的數到底有多少個(tot代表集合裏面元素的總數)。如果大於或等於 k 則存在比這個數大且是第k大的數, 接下來只要二分查找即可!

瞎搞:當時沒有想到二分, 而是直接丟進一個multiset中, 讓後進行叠代查找操作, 別說了, TEL得好慘……

技術分享
#include<bits/stdc++.h>
#define lowbit(i) (i&(-i))
using namespace std;
const int maxn = 1e5+1;
int c[maxn];
inline void add(int i, int val)
{
    while(i<=100000){
        c[i] += val;
        i += lowbit(i);
    }
}
int sum(int
i) { int ans = 0; while(i>0){ ans += c[i]; i -= lowbit(i); } return ans; } int vis[maxn]; int Bin_search(int L, int R, int key, int index) { int mid; while(L < R){ mid = L + ((R-L)>>1); if(sum(mid) - sum(index) < key) L = mid + 1
; else R = mid; } return R; } int main(void) { int n; while(~scanf("%d", &n) && n){ memset(c, 0, sizeof(c)); memset(vis, 0, sizeof(vis)); int command; int tot = 0; int M = 0; for(int t=1; t<=n; t++){ scanf("%d", &command); if(command==0){ int temp; scanf("%d", &temp); if(temp>M) M = temp; vis[temp]++; add(temp, 1); tot++; } else if(command==1){ int temp; scanf("%d", &temp); if(vis[temp]){ tot--; add(temp, -1); vis[temp]--; }else{ puts("No Elment!"); } } else{ int a, b; int ans; scanf("%d%d", &a, &b); if(tot-sum(a) >= b){ int ans = Bin_search(a, M, b, a); printf("%d\n", ans); }else{ puts("Not Find!"); } } } } return 0; }
View Code

HDU 2852 KiKi's K-Number (樹狀數組 && 二分)