【平衡树】第K小数
Time Limit:150000MS Memory Limit:1655360K
Case Time Limit:15000MS
Description
现在已有N个整数,你有以下三种操作:
A 表示加入一个值为A的整数
B 表示删除其中值为B的整数
K 表示输出这些整数中第K小的数
Input
第一行,两个整数N,M,表示最开始有N个整数,总共有M个操作
第二行用空格隔开的N个整数
接下来M行,每行表示一个操作
Output
若干行,一行一个整数,表示所求的第K小的数字
Sample Input
5 5
6 2 7 4 9
1 8
1 6
3 10
2 4
3 3
Sample Output
0
7
Hint
注意:如果有多个大小相同的数字,只把他们看做一个数字,如样例。
若找不到第K小的数,输出0
数据范围:
0<=N<=2,000,000
M<=1,000,000
-1,000,000,000<=每个整数<=1,000,000,000
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
struct node{
long long ls,rs,sum;
};
node tree[40000005];
long long n,m,tot=1,cnt=0;
long long dt=1;
bool flag;
void add(long long &p,long long l,long long r,long long k){
if(k<l||r<k)return;
long long mid=(l+r)>>1;
if(l==r){
if(p==0){
p=++tot;
if(dt==1){
tree[p].sum+=dt;
flag=true;
}
return;
}
else if(tree[p].sum==0){
if(dt==1){
tree[p].sum+=dt;
flag=true;
}
return;
}
else if(tree[p].sum>=1){
if(dt==-1){
tree[p].sum+=dt;
flag=true;
}
return;
}
else return;
}
else if(p==0){
p=++tot;
}
add(tree[p].ls,l,mid,k);
add(tree[p].rs,mid+1,r,k);
if(flag)tree[p].sum+=dt;
}
long long query(long long p,long long l,long long r,long long k){
long long mid=(l+r)>>1;
if(l==r)return l;
else if(tree[tree[p].ls].sum>=k)return query(tree[p].ls,l,mid,k);
else return query(tree[p].rs,mid+1,r,k-tree[tree[p].ls].sum);
}
int main(){
long long i,j,k;
long long temp=1;
scanf("%I64d%I64d",&n,&m);
for(i=1;i<=n;i++){
long long a;
scanf("%I64d",&a);
a+=1000000001;
flag=false;
add(temp,1,2000000001,a);
if(flag)cnt++;
}
while(m--){
long long x,a;
scanf("%I64d%I64d",&x,&a);
if(x==1){
flag=false;
dt=1;
a+=1000000001;
add(temp,1,2000000001,a);
if(flag)cnt++;
}
if(x==2){
flag=false;
dt=-1;
a+=1000000001;
add(temp,1,2000000001,a);
if(flag)cnt--;
}
if(x==3){
if(a>cnt)printf("0\n");
else printf("%I64d\n",query(temp,1,2000000001,a)-1000000001);
}
}
//printf("%I64d",cnt);
}