HDU 2852 (树状数组+无序第K小)

题目大意:操作①:往盒子里放一个数。操作②:从盒子里扔掉一个数。操作③:查询盒子里大于a的第K小数。

解题思路

由于模型是盒子,而不是序列,所以可以用树状数组的顺序维护+逆序数思想。

放一个数

Add(val,1)Add(val,1)

类似维护逆序数的方法,对应位置上计数+1。

注意Add的while范围要写成while(x<maxn)while(x<maxn)

如果范围不是最大,那么会导致某些sum[x]不会被更新。

删一个数

判断:getSum(val)getSum(val1)=0getSum(val)−getSum(val−1)=0

可以Hash处理,但是没有必要。如果没有val这个数,那么getSum(val)=getSum(val1)getSum(val)=getSum(val−1)是必然的。

删除:Add(val,1)Add(val,−1)

即加上-1,撤销之前的操作。

查询

查询比较麻烦。

首先要判断getSum(maxn1)getSum(val)>=kgetSum(maxn−1)−getSum(val)>=k

然后,将查询大于a的第K小数转化为大于1的第X+K小数。

其中X=getSum(val)X=getSum(val)。然后,对区间[1,maxn][1,maxn]进行二分。

二分处理手段比较特殊,主要是由于有重复的数,所以直接找出argminmidgetSum(mid)=X+Karg⁡minmidgetSum(mid)=X+K是不行的。

getSum(mid)=X+KgetSum(mid)=X+K有时候并不能二分找到。

解决方法是:

R=mid(getSum(mid)<=X+K)

L=mid(other)

这样,如果没有二分到,会最近的最小R作为结果。

ans=R

AC代码:

#include<stdio.h>
#include<string.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

 前面思路还可以,但到后面的查询操作就不能很快解决导致TLE,问题是出在查询无序第k小问题身上,以后在解决无序第K小问题的时候,可以考虑这种算法

posted @ 2018-06-02 17:00  shuai_hui  阅读(126)  评论(0编辑  收藏  举报