#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 100005
struct hh
{
int siz;//siz以这个点为根的子树大小
int val;//val值满足二叉搜索树的性质(lch<now<rch)
int key;//key值满足堆的性质(大堆或小堆)
int lch;//lch左子节点
int rch;//rch右子节点
}t[maxn];
int tot,seed=233,root=1;
int Rand(); //给k赋予随机优先级
inline ll read()//快速读入程序
{
char kr=0;
char ls;
for(;ls>'9'||ls<'0';kr=ls,ls=getchar());
ll xs=0;
for(;ls>='0'&&ls<='9';ls=getchar())
{
xs=xs*10+ls-48;
}
if(kr=='-')
xs=0-xs;
return xs;
}
int Rand()
{//随机key值
return seed=int(seed*482711ll%2147483647);/**/
}
int NEW(int val)//新建节点
{
t[++tot].siz=1;
t[tot].val=val;
t[tot].key=Rand();
t[tot].lch=t[tot].rch=0;
return tot;
}
void update(int now)//维护子树大小
{
t[now].siz=t[t[now].lch].siz+t[t[now].rch].siz+1;
}
void split(int now,int &a,int &b,int val)//拆分操作
{//now为原treap,a为左子树,b为右子树,val为判定值(注意传地址符)
if(now==0)
{
a=b=0;//若now=0分割完毕
return ;
}
if(t[now].val<=val)//因为now左子树中的所有值都小于now的值,所以若now属于左子树,那么他们都属于左树递归now的右子树;
a=now,split(t[now].rch,t[a].rch,b,val);//a=now已经使a的右子树=now的右子树,不再递归a的右子树;
else//同上now的右子树也都属于左树,递归左子树;
b=now,split(t[now].lch,a,t[b].lch,val);
update(now);//因为后面会用到左(右)树的siz所以更新维护
}
void merge(int &now,int a,int b)//合并操作,now新树
{
if(a==0||b==0)
{
now=a+b;//若某个数已空,则将另一个子树整体插入
return ;
}
//按照key值合并(堆性质)
if(t[a].key<t[b].key)
//若a树key值<b树,那么b树属于a树的后代,因为b树恒大于a树,那么b树一定属于a树的右后代,a的左子树不变,直接赋值给now,递归合并a的右子树和b
now=a,merge(t[now].rch,t[a].rch,b);
else//同理,a树一定是b树的左儿子,递归合并b的右子树和a
now=b,merge(t[now].lch,a,t[b].lch);
update(now);//维护一下合并后的树的大小 (siz)
}
void insert(int val)//插入一个数
{
int x=0,y=0,z;
z=NEW(val);//新建节点z,作为z树
split(root,x,y,val);//将树分为两部分,x树为<=待插入的值,y树大于
merge(x,x,z);//合并x树和新节点z(树),赋值给x树
merge(root,x,y);//合并新x树和y树,赋值给根
}
void delet(int val)//删除一个数
{
int x=0,y=0,z=0;
split(root,x,y,val);//分为x树为<=待删除,y树大于
split(x,x,z,val-1);//x树分为新x树<待删除,z树等于待删除
merge(z,t[z].lch,t[z].rch);//合并z树的左右儿子,赋给z树,即丢弃z树的根节点(实现删除)
merge(x,x,z);
merge(root,x,y);//合并,不再重复
}
void get_rank(int val)//求k数的排名
{
int x=0,y=0;
split(root,x,y,val-1);//分为小于待查找的x树和大于等于的y树
printf("%d\n",t[x].siz+1);//即为待查找值的编号
merge(root,x,y);//合并
}
void find(int now,int rank)//兼容
{//兼容性函数->用来 查询排名第k位的数,查询k的前驱、后继
while(t[t[now].lch].siz+1!=rank)
{
if(t[t[now].lch].siz>=rank)
now=t[now].lch;//若左子树大小大于rank,找左子树
else
{
rank-=(t[t[now].lch].siz+1),now=t[now].rch;
//找右子树(rank-左子树大小-树根(大小为1))号的元素
}
}
printf("%d\n",t[now].val);
}
void get_val(int rank)//求排名第k为的数
{
find(root,rank);//find查找即可
}
void get_pre(int val)//求k的前驱
{
int x=0,y=0;
split(root,x,y,val-1);//x树为<=val-1值即小于val值
find(x,t[x].siz);//在小于val值中找到最大的(编号为siz)就是前驱
merge(root,x,y);//合并
}
void get_nxt(int val)
{
int x=0,y=0;
split(root,x,y,val);//x树小于等于val值,那么y树大于val值
find(y,1);//在y树中找最小的,即为后继
merge(root,x,y);//合并
}
int main()
{
int i,j,k,m;
NEW(2147483627);//初始化虚节点
t[1].siz=0;//siz为0,不算虚节点的大小
m=read();
while(m--)
{
j=read();k=read();
if(j==1) insert(k);//插入一个数k
if(j==2) delet(k);//删除一个数k
if(j==3) get_rank(k);//查询k数的排名
if(j==4) get_val(k);//查询排名第k位的数
if(j==5) get_pre(k);//求k的前驱(定义为小于x,且为最大的数)
if(j==6) get_nxt(k);//求k的后继(定义为大于x,且为最小的数)
}
return 0;
}