题目大意:
给你一个队列,里面有三种操作。
(0 ) 往队列里压入一个值为 X 的数
(1 ) 从队列里弹出一个值为 X 的数,如果没有,输出 “No Elment!” ,如果有,弹出这个数。(如果队列中有多个x ,只弹出一个)
( 2 ) 找出队列里比a 大的第k个数。如果有,输出这个数的值 ,如果没有,输出“Not Find!”
树状数组,num[x] 记录x 在全队列中倒数的排名 (倒数)。 这样,一旦在x处插入一个值,用树状数组给后面的数排名加一就行了,反之,弹出的时候,后面的每个排名-1。
不过要注意,因为一个队列中x的个数可能不止一个,所以理论上x的排名应该是一个区间,但在程序中num[x]记录排名最大的那个x(num[x] 最大)。
更新解决了,自然要解决查找的问题。因为num[x] 中是单调递增的,所以可以用二分查找,找到一个x 使得 num[x]= num[a] +k。
但是num[x] 理论上应该是一个区间,举例说 1 2 2 2 2 五个数, num[2] 理论上的范围应该是2到5,但因为我们记录x最大的那个,num[2]的值为5,所以这时候不是精确查找,要查找一个上界,就是找到一个x 使得 num[x]>= num[a] +k 。 一个二分的变形,不会的可以参考http://www.cnblogs.com/ider/archive/2012/04/01/binary_search.html
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100010
int num[N];
int f[N];
int lowbit(int x)
{
return x&-x;
}
void updata(int x,int v)
{
while(x<=100000)
{
num[x]+=v;
x+=lowbit(x);
}
}
int query(int x)
{
int ret=0;
while(x>0)
{
ret+=num[x];
x-=lowbit(x);
}
return ret;
}
int find(int pos,int x)
{
int l=pos+1,r=100000,mid=(l+r)>>1;
while(l<r)
{
if(query(mid)>=x) r=mid; //二分查找的变形,查找上界
else l=mid+1;
mid=(l+r)>>1;
}
return mid;
}
int main()
{int n;
int x,y;
while(cin>>n)
{memset(num,0,sizeof(num));
memset(f,0,sizeof(f));
while(n--)
{
scanf("%d",&x);
if(x==0)
{
scanf("%d",&x);
++f[x];
updata(x,1); //比x大的i(包括x),num[i]排名都加一
}
else if(x==1)
{
scanf("%d",&x);
if(f[x])
{
--f[x];
updata(x,-1);//弹出,比x大的i(包括x),num[i]排名都减一
}
else
{
printf("No Elment!\n");
}
}
else
{
scanf("%d%d",&x,&y);
if(query(100000)-query(x)<y)
{
printf("Not Find!\n");
}
else
{
printf("%d\n",find(x,query(x)+y));//找到一个数i,使得num[i]>=num[x]+k
}
}
}
}
return 0;
}