巴蜀OJ 1322 第K小数

1322 -- 【练习试题】第K小数

Description

  现在已有N个整数,你有以下三种操作:
1 A:表示加入一个值为A的整数;
2 B:表示删除其中值为B的整数;
3 K:表示输出这些整数中第K小的数;

Input

第一行,两个整数N,M,表示最开始有N个整数,总共有M个操作
第二行用空格隔开的N个整数
接下来M行,每行表示一个操作

Output

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

Sample Input

5 5 6 2 7 4 91 81 63 102 43 3

Sample Output

07

Hint

【注意】:如果有多个大小相同的数字,只把他们看做一个数字,如样例。 若找不到第K小的数,输出0
【数据范围】
0<=N<=2,000,000
M<=1,000,000
-1,000,000,000<=每个整数<=1,000,000,000


【题目分析】
    又是一道简单的模板题,但是由于我太困了,不想思考到底在哪里up它的值了,然而up并不影响时间复杂度。我就多加了几个(#(滑稽))。

【代码】
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
using namespace std;
struct node{
	int l,r,size,v,rnd;
}tr[2010000];
int root=0,cnt=0,ans=0;
inline void up(int k)
{tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+1;}
inline void rturn(int &k)
{
	int t=tr[k].l;
	tr[k].l=tr[t].r;
	tr[t].r=k;
	tr[t].size=tr[k].size;
	up(k);
	up(t);
	k=t;
}
inline void lturn(int &k)
{
	int t=tr[k].r;
	tr[k].r=tr[t].l;
	tr[t].l=k;
	tr[t].size=tr[k].size;
	up(k);
	up(t);
	
	k=t;
}
inline void ins(int &k,int x)
{
	if (k==0){++cnt;k=cnt;tr[k].v=x;tr[k].rnd=rand();tr[k].size=1;return;}
	if (x==tr[k].v) return;up(k);
	if (x>tr[k].v){ins(tr[k].r,x);up(k);if (tr[tr[k].r].rnd>tr[k].rnd);lturn(k);up(k);return;}
	if (x<tr[k].v){ins(tr[k].l,x);up(k);if (tr[tr[k].l].rnd>tr[k].rnd);rturn(k);up(k);return;}
}
inline int qrank(int k,int x)
{
	if (k==0) return 0;
	if (x>tr[tr[k].l].size+1) return qrank(tr[k].r,x-tr[tr[k].l].size-1);
	else if (x<=tr[tr[k].l].size) return qrank(tr[k].l,x);
	else return tr[k].v;
}
inline void del(int & k,int x)
{
	if (k==0) return ;
	if (tr[k].v==x)
	{
		if (tr[k].l*tr[k].r==0) k=tr[k].l+tr[k].r;
		else if (tr[tr[k].l].rnd>tr[tr[k].r].rnd) up(k),rturn(k),up(k),del(k,x),up(k);
		else up(k),lturn(k),up(k),del(k,x),up(k);
		return ;
	}
	up(k);
	if (tr[k].v>x) {del(tr[k].l,x);up(k);return;}
	else del(tr[k].r,x),up(k);
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i) {
		int x;
		scanf("%d",&x);
		ins(root,x);
	}
	for (int i=1;i<=m;++i){
		int a,b;
		scanf("%d%d",&a,&b);
		switch(a)
		{
			case 1:ins(root,b);break;
			case 2:del(root,b);break;
			case 3:printf("%d\n",qrank(root,b));break;
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值