您的位置:首页 > 其它

【题】【线段树(动态开点&负点)】NKOJ 1922 第K小数

2016-07-24 19:33 330 查看
NKOJ 1922 第K小数

时间限制 : 150000 MS 空间限制 : 1655360 KB

问题描述

现在已有N个整数,你有以下三种操作:

A 表示加入一个值为A的整数

B 表示删除其中值为B的整数

K 表示输出这些整数中第K小的数

输入格式

第一行,两个整数N,M,表示最开始有N个整数,总共有M个操作

第二行用空格隔开的N个整数

接下来M行,每行表示一个操作

输出格式

若干行,一行一个整数,表示所求的第K小的数字

样例输入

5 5

6 2 7 4 9

1 8

1 6

3 10

2 4

3 3

样例输出

0

7

提示

注意:如果有多个大小相同的数字,只把他们看做一个数字,如样例。

若找不到第K小的数,输出0

数据范围:

0<=N<=2,000,000

M<=1,000,000

-1,000,000,000<=每个整数<=1,000,000,000

思路:

范围太大,动态建立线段树:每次加入一个数,就将线段树对应叶节点的值改为1,若无该节点就建立;每次减少,对应叶节点改为0;每次查找,先查找左儿子是否有k个数,不足说明该找右儿子。

注意先判断是否存在左右儿子

#include<cstdio>
#include<iostream>
using namespace std;

struct tree{int a,b,val;tree *le,*ri;};

tree NBHB,*temp;
int k;
bool mark=false;
//...................................................................
inline void in_(int &d)
{
bool mark=false;char t=getchar();
while(t<'0'||t>'9'){if(t=='-') mark=true;t=getchar();}
for(d=0;t>='0'&&t<='9';t=getchar())d=(d<<3)+(d<<1)-'0'+t;
if(mark)d=-d;
}
char o[100];
inline void out_(int x)
{
int l=1;
if(x<0) x=-x,putchar('-');
if(!x) putchar('0');
for(;x;x/=10) o[l++]=x%10+'0';
for(l--;l;l--)putchar(o[l]);
putchar('\n');
}
//...................................................................
void add(tree *t)
{
if(t->a==t->b)
{
t->val=1;
return ;
}
int mid=t->a+t->b,x=t->a,y=t->b;
mid=mid<0?mid/2-1:mid>>1;
if(k<=mid)
{
if(t->le==NULL)
{
t->le=new tree;
t->le->a=x,t->le->b=mid,t->le->le=t->le->ri=NULL;
}
add(t->le);
}
if(k>mid)
{
if(t->ri==NULL)
{
t->ri=new tree;
t->ri->a=mid+1,t->ri->b=y,t->ri->le=t->ri->ri=NULL;
}
add(t->ri);
}
t->val=0;
if(t->le!=NULL) t->val+=t->le->val;
if(t->ri!=NULL) t->val+=t->ri->val;
}
void del(tree *t)
{
if(mark) return ;
if(t->a==t->b)
{
t->val=0;
return ;
}
int mid=t->a+t->b,x=t->a,y=t->b;
mid=mid<0?mid/2-1:mid>>1;
if(k<=mid)
{
if(t->le==NULL)
{
mark=true;
return;
}
del(t->le);
}
if(k>mid)
{
if(t->ri==NULL)
{
mark=true;
return;
}
del(t->ri);
}
t->val=0;
if(t->le!=NULL) t->val+=t->le->val;
if(t->ri!=NULL) t->val+=t->ri->val;
}

int find(tree *t,int k)
{
if(t->val<k) return 0;
if((*t).a==(*t).b) return t->b;
if(t->le!=NULL)
{
temp=t->le;
if(temp->val>=k) return find(temp,k);
else return find(t->ri,k-temp->val);
}
else return find(t->ri,k);
}
//...................................................................
int main()
{
NBHB.a=-1000000000,NBHB.b=1000000000,NBHB.le=NULL,NBHB.ri=NULL;
int n,m;in_(n),in_(m);
for(int i=1;i<=n;i++)
{
in_(k);
add(&NBHB);
}
for(int i=1,c;i<=m;i++)
{
in_(c),in_(k);
if(c==1) add(&NBHB);
else if(c==2)
{
mark=false;
del(&NBHB);
}
else out_(find(&NBHB,k));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: