题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2852
大致题意:
有三种操作:
第一种:向容器中加入数字A。
第二种:从容器中删除数字A,若容器中不存在该数则输出"No Elment!"
第三种:输入A,K;求容器中比A大的数中的第K个数,若不存在则输出"Not Find!"
线段树每个节点存对应区域中共有多少个有效的数字,并实现单点更新。
对于操作一和操作二很另开数组容易实现。实现操作三时先求出比A大的数的个数B,接下来求有效元素中第B+K个数。
(同样大小的数可能有多个,都需要计数)
segTree[1]代表整个容器中有多少元素;显然,若segTree[1]<B+K则需要输出"Not Find!"。
查找区域中一共有多少有效元素实现简单也较容易理解,感觉上理解求容器中第K+B大的过程稍微难理解一些。
首先求出当前节点左儿子节点代表区域中有效元素个数,即segTree[lson]。
为求出当前区域中第K大的数,需要将K与segTree[lson]进行比较。若K<=segTree[lson]则说明第K大的数在当前节点左儿子代表区域中,
否则在右儿子节点代表区域中。若在右儿子代表的区域中需要把K修改为K-segTree[lson]。当查找到叶子节点时,该节点即为所求。
#include<iostream>
#include<cstring>
#include<cstdio>
#define lson node<<1,l,(l+r)/2
#define rson node<<1|1,(l+r)/2+1,r
using namespace std;
const int N = 1e5+10;
int segTree[N<<2];
int vis[N];
void update(int node,int l,int r,int pos,int n)
{
if (l==r) segTree[node] += n;
else
{
int mid = (l+r)>>1;
if (pos<=mid) update(lson,pos,n);
else update(rson,pos,n);
segTree[node] = segTree[node<<1] + segTree[node<<1|1];
}
}
int query(int node,int l,int r,int s,int e)
{
if (l==r) return segTree[node];
else if (l>=s && r<=e) return segTree[node];
else
{
int ans = 0;
int mid = (l+r)>>1;
if (mid>=e)
ans += query(lson,s,e);
else if (mid<s)
ans += query(rson,s,e);
else
{
ans += query(lson,s,mid);
ans += query(rson,mid+1,e);
}
return ans;
}
}
int getans(int node,int l,int r,int cnt)
{
if (l==r) return l;
else
{
if (cnt<=segTree[node<<1])
return getans(lson,cnt);
else
return getans(rson,cnt-segTree[node<<1]);
}
}
int main()
{
int cnt;
int op,a,k;
while (scanf("%d",&cnt)==1)
{
memset(segTree,0,sizeof (segTree));
memset(vis,0,sizeof (vis));
for (int i=0;i<cnt;i++)
{
scanf("%d%d",&op,&a);
if (op==0)
{
vis[a]++;
update(1,1,N,a,1);
}
else if (op==1)
{
if (!vis[a])
{
printf("No Elment!\n");
}
else
{
vis[a]--;
update(1,1,N,a,-1);
}
}
else
{
scanf("%d",&k);
int t = query(1,1,N,1,a);
if (t+k>segTree[1])
{
printf("Not Find!\n");
}
else
{
printf("%d\n",getans(1,1,N,t+k));
}
}
}
}
return 0;
}