/*
P3369 splay平衡树
一种数据结构,支持插入、删除、查询排名、查询前驱后继
右旋操作:
u上移替代 fa,保留左儿子,丢掉右儿子
fa 下移,保留 fa 原本的右儿子,同时自己变成 u 的右儿子
fa 的左儿子替换成 u 的右儿子
总而言之:
儿子变父亲,儿子的右儿子变左孙子
左旋同理
----------------------------
伸展操作
如果 xyz 是直线型,则连续旋转两次 x
如果 xyz 是折线型,则先下沉 y 再旋转 x
*/
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct NODE{
int s[2],fa;//节点联系
int val,cnt,sz;//节点信息
void init(int f,int v){//初始化
fa=f, val=v;
cnt=sz=1;
}
}tr[N];
int rt,idx;
void push_up(int p){
tr[p].sz=tr[tr[p].s[0]].sz+tr[tr[p].s[1]].sz+tr[p].cnt;
}
void rotate(int x){//旋转
int y=tr[x].fa, z=tr[y].fa;
if(x==tr[y].s[0]){//右旋
//z儿子从 x 变成 y
tr[x].fa=z;
if(y==tr[z].s[0]) tr[z].s[0]=x;
else tr[z].s[1]=x;
//x儿子过继给y
tr[y].s[0]=tr[x].s[1];
//xy关系互换
tr[x].s[1]=y;
tr[y].fa=x;
}else{//左旋
tr[x].fa=z;
if(y==tr[z].s[0]) tr[z].s[0]=x;
else tr[z].s[1]=x;
tr[y].s[1]=tr[x].s[0];
tr[x].s[0]=y;
tr[y].fa=x;
}
push_up(y), push_up(x);//从下向上push_up
}
void splay(int x,int k){
//k > 0时把 x 旋转到 x下面
//k = 0时把 x 旋转到 rt
while(tr[x].fa!=k){
int y=tr[x].fa, z=tr[y].fa;
if(z!=k){
if((tr[y].s[0]==x)^(tr[z].s[0]==y)) rotate(x);//折线型
else rotate(y);//直线形
//折转底,直转中
}
rotate(x);
}
if(k==0) rt=x;//更新根节点
}
void find(int v){//找到 v,并把 v 旋转到 rt
int x=rt;//x表示 v 的位置
while(tr[x].s[v>tr[x].val] && v!=tr[x].val){
x=tr[x].s[v>tr[x].val];
//tr[x].s[v>tr[x].val] 指向的就是 v 所在的子树
//如果找不到 v,就找最靠近的小于v的点
}
splay(x,0);
}
int get_pre(int v){//v 的前驱编号
find(v);//把 v 转移到 rt 上
int x=rt;
if(tr[x].val<v) return x; //相当于v不存在
x=tr[x].s[0];
while(tr[x].s[1]) x=tr[x].s[1];//尽可能靠右走,这样会更大
return x;
}
int get_suc(int v){
find(v);
int x=rt;
if(tr[x].val>v) return x;
x=tr[x].s[1];
while(tr[x].s[0]) x=tr[x].s[0];
return x;
}
void del(int v){//删除
int pre=get_pre(v);
int suc=get_suc(v);
splay(pre,0);//pre旋到rt
splay(suc,pre); //suc旋到pre下面
int del=tr[suc].s[0];
//画图可知删除点是后继的 ls
//可以证明这样旋转,del一定会被转到叶子
if(tr[del].cnt>1){
tr[del].cnt--;
splay(del,0);
}else{
tr[suc].s[0]=0;//清空连边
splay(suc,0);
}
}
void insert(int v){
int x=rt, p=0;
while(x && tr[x].val!=v){
p=x;//p就是最末端的点
x=tr[x].s[v>tr[x].val];//x不断下找直到找对应值
}
if(x) tr[x].cnt++;//存在
else{//不存在
x=++idx;
tr[p].s[v>tr[p].val]=x;
tr[x].init(p,v);//初始化
}
splay(x,0);
}
int get_rk(int v){ //排名
insert(v);
int res=tr[tr[rt].s[0]].sz;
del(v);
return res;
}
int get_val(int k){//求排名k的值 (记得+1后再找,因为存在-INF)
int x=rt;
while(1){
int y=tr[x].s[0];
if(tr[y].sz+tr[x].cnt < k){//rs
k-=tr[y].sz+tr[x].cnt;
x=tr[x].s[1];
}else{//ls或者 x
if(k<=tr[y].sz) x=tr[x].s[0];//还在ls
else break;//就在当前点
}
}
splay(x,0);
return tr[x].val;
}
int n;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int INF=1e9+7;
insert(-INF),insert(INF);
cin>>n;
while(n--){
int op,x;
cin>>op>>x;
if(op==1) insert(x);
if(op==2) del(x);
if(op==3) cout<<get_rk(x)<<'\n';
if(op==4) cout<<get_val(x+1)<<'\n';//记得+1
if(op==5) cout<<tr[get_pre(x)].val<<'\n';
if(op==6) cout<<tr[get_suc(x)].val<<'\n';
}
return 0;
}
/*
Hack
20
1 964673
5 968705
4 1
3 964673
5 965257
1 915269
1 53283
3 964673
3 53283//死循环位置
3 53283
1 162641
5 973984
1 948119
2 915269
2 53283
6 959161
1 531821
1 967521
2 531821
1 343410
*/