题意:给定一个容器,里面存放各种数值,规定三个操作,一个是在容器中增加一个数值,一个是在容器中删掉一个数值,一个是询问容器中比a大的数中第k大的数,将其输出。如果在删除过程中没有这个数,则输出"No Elment!",如果容器中没有比a大的第k个数,则输出"Not Find!".
此题因为是增加和删除元素的值,所以比较容易往树状数组的方向想,用树状数组当容器。采用一个标记数组来标记某个数值在容器中是否有。对于询问容器中比a大的第k个数,我们采用二分法,对a后面比它大的数进行二分,这里注意一下二分时必须是查看某点至a点有多少个比它大的,用Sum(mid) - Sum(a)就可以得到,我们这里就只要二分mid就可以了。
方法比较容易想到,代码的实现就必须要对树状数组理解清楚以及二分的思想及其步骤都要明确。
下面附上代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define N 100010
#define Lowbit(x) ((x)&(-x))
int C[N];
bool vis[N];
void add(int x,int num)
{
while(x < N)
{
C[x] += num;
x += Lowbit(x);
}
}
int Sum(int x)
{
int ans = 0;
while(x > 0)
{
ans += C[x];
x -= Lowbit(x);
}
return ans;
}
int binarysearch(int l,int k){
int mid, left, right, tmp;
left = l + 1;
right = N - 1;
if(Sum(right) - Sum(l) < k)return -1;
while(left <= right){
mid = (left + right) >> 1;
tmp = Sum(mid) - Sum(l);
if(tmp == k){
if(vis[mid]){
return mid;
}
right = mid - 1;
}
else if(tmp > k){
if(Sum(mid - 1) - Sum(l) < k)return mid;
right = mid - 1;
}
else {
left = mid + 1;
}
}
return -1;
}
int main()
{
int p, n, m, T, e, a, k, l, r, mid;
while(~scanf("%d",&T))
{
memset(C,0,sizeof(C));
memset(vis,0,sizeof(vis));
while(T--)
{
scanf("%d",&p);
switch(p)
{
case 0:
scanf("%d",&e);
add(e,1);
vis[e] = 1;
break;
case 1:
scanf("%d",&e);
m = Sum(e) - Sum(e-1);
if(!m)printf("No Elment!\n");
else add(e,-1);
if(m == 1)vis[e] = 0;
break;
case 2:
scanf("%d%d",&a,&k);
m = binarysearch(a,k);
if(m == -1)
printf("Not Find!\n");
else
printf("%d\n",m);
break;
}
}
}
return 0;
}