HDU 2852 KiKi's K-Number (树状数组 && 二分)
题意 : 给出对容器的总操作次数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; }