1322 -- 【练习试题】第K小数
Description
现在已有N个整数,你有以下三种操作:
1 A:表示加入一个值为A的整数;
2 B:表示删除其中值为B的整数;
3 K:表示输出这些整数中第K小的数;
1 A:表示加入一个值为A的整数;
2 B:表示删除其中值为B的整数;
3 K:表示输出这些整数中第K小的数;
Input
第一行,两个整数N,M,表示最开始有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
【数据范围】
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;
}
}
}