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;
}
View Code

 

转载于:https://www.cnblogs.com/LiHior/p/6917081.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值