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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2852

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

解题思路

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

对应的树状数组Solution:

放一个数

$Add(val,1)$

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

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

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

删一个数

判断:$getSum(val)-getSum(val-1)=0$

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

删除:$Add(val,-1)$

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

查询

查询比较麻烦。

首先要判断$getSum(maxn-1)-getSum(val)>=k$

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

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

二分处理手段比较特殊,主要是由于有重复的数,所以直接找出$\arg \min \limits_{mid} getSum(mid)=X+K$是不行的。

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

解决方法是:

$\left\{\begin{matrix}
R=mid \quad (getSum(mid)<=X+K)\\
\\
L=mid \quad (other)
\end{matrix}\right.$

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

$ans=R$

代码

#include "cstdio"
#include "map"
#include "cstring"
#include "algorithm"
using namespace std;
#define LL long long
#define maxn 100005
LL sum[maxn];
int val,n,kth,cmd;
int lowbit(int x) {return x&(-x);}
LL getSum(int x)
{
    LL ret=0;
    while(x>0)
    {
        ret+=sum[x];
        x-=lowbit(x);
    }
    return ret;
}
void update(int x,int s)
{
    while(x<maxn)
    {
        sum[x]+=s;
        x+=lowbit(x);
    }
}
LL query(int a,int k)
{
    LL low=getSum(a),res;
    low+=k;
    int l=1,r=maxn-1,m;
    while(l<r-1)
    {
        m=l+(r-l)/2;
        res=getSum(m);
        if(res>=low) r=m;
        else l=m;
    }
    return r;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&cmd);
            if(cmd==0)
            {
                scanf("%d",&val);
                update(val,1);
            }
            else if(cmd==1)
            {
                scanf("%d",&val);
                LL key=getSum(val)-getSum(val-1);
                if(key==0) printf("No Elment!\n");
                else update(val,-1);
            }
            else
            {
                scanf("%d%d",&val,&kth);
                if(getSum(maxn-1)-getSum(val)<kth) printf("Not Find!\n");
                else
                {
                   LL ans=query(val,kth);
                   printf("%I64d\n",ans);
                }
            }
        }
    }
}

 

posted @ 2015-05-29 11:45  Physcal  阅读(693)  评论(0编辑  收藏  举报