題目鏈接: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;
}