import java.util.*;
class Main{
static class Node{
int cnt, size, high, key;
Node left, right;
public Node(int key){
this.key = key;
cnt = size = high = 1;
}
}
static final int INF = 0x3f3f3f3f;
static Node root;
/*
基本操作 总会用到 后面省事
*/
static int getHigh(Node node){
return node!=null?node.high:0;
}
static int getSize(Node node){
return node!=null?node.size:0;
}
static int getBalance(Node node){
return getHigh(node.left) - getHigh(node.right);
}
static void pushup(Node node){
node.high = Math.max(getHigh(node.left), getHigh(node.right)) + 1;
node.size = getSize(node.left) + getSize(node.right) + node.cnt;
}
/*
旋转操作
*/
static Node rightRoate(Node node){//右旋
Node p = node.left;
node.left = p.right;
p.right = node;
pushup(p.right);
pushup(p);
return p;
}
static Node leftRoate(Node node){//左旋
Node p = node.right;
node.right = p.left;
p.left = node;
pushup(p.left);
pushup(p);
return p;
}
static Node leftRightRoate(Node node){//先左旋在右旋
node.left = leftRoate(node.left);
pushup(node);
return rightRoate(node);
}
static Node rightLeftRoate(Node node){
node.right = rightRoate(node.right);
pushup(node);
return leftRoate(node);
}
/*
平衡当前结点node, 这里应该知道几点性质:
(1)能够平衡的结点一定是从树低到上 第一个不平衡点;
(2)当前结点 左右子树中 被插入的一侧 被插之前一定是平衡的(如果不是平衡的, 高度不会发生变化)
(3)平衡前后,当前结点位置的树高度不变(实际这个结点已经换了)
*/
static Node balance(Node node){
int balanFactor = getBalance(node);
//pushup(node);
if(Math.abs(balanFactor)<2){
pushup(node);
return node;
}
//左面高
if(balanFactor>1){
int leftBalanFactor = getBalance(node.left);
if(leftBalanFactor>=0) return rightRoate(node);//插入时候 这里不是大于0就是小于0 绝不会等于零, 删除时会发生为0。
return leftRightRoate(node);
}
//右面高
int rightBalanFactor = getBalance(node.right);
if(rightBalanFactor>0) return rightLeftRoate(node);//同上
return leftRoate(node);
}
/*
插入数值 x。
删除数值 x(若有多个相同的数,应只删除一个)。
查询数值 x 的排名(若有多个相同的数,应输出最小的排名)。
查询排名为 x 的数值。
求数值 x 的前驱(前驱定义为小于 x 的最大的数)。
求数值 x 的后继(后继定义为大于 x 的最小的数)。
*/
//插入
static Node insert(Node node, int key){
if(node==null) return new Node(key);
if(key==node.key){
node.cnt++;
pushup(node);
}
if(key<node.key){
node.left = insert(node.left, key);
pushup(node);
node = balance(node);
}else if(key>node.key){
node.right = insert(node.right, key);
pushup(node);
node = balance(node);
}
return node;
}
//删除(最麻烦)
static Node remove(Node node, int key){
if(node==null) return null;
if(key<node.key){
node.left = remove(node.left, key);
pushup(node);
node = balance(node);
assert(Math.abs(getBalance(node))>1);
return node;
}
else if(key>node.key){
node.right = remove(node.right, key);
pushup(node);
node = balance(node);
assert(Math.abs(getBalance(node))>1);
return node;
}
if(node.cnt>1){
node.cnt--;
pushup(node);
}
else{
if(node.left==null&&node.right==null) return null;
//这里需要下面两个辅助函数 分别来处理查找前驱或者后继 替换当前的点 并且删除前驱或后继在树中的原来位置
if(node.left!=null){
node.left = getPreNodeAndDel(node.left, node);
pushup(node);
node = balance(node);
}else{
node.right = getNextNodeAndDel(node.right, node);
pushup(node);
node = balance(node);
}
}
// pushup(node);
return node;
}
static Node getPreNodeAndDel(Node node, Node cur){//寻找cur的前驱,并覆盖cur的值
if(node.right==null){
cur.cnt = node.cnt;
cur.key = node.key;
return node.left;
}
node.right = getPreNodeAndDel(node.right, cur);
pushup(node);
return balance(node);
}
static Node getNextNodeAndDel(Node node, Node cur){
if(node.left==null){
cur.cnt = node.cnt;
cur.key = node.key;
return node.right;
}
node.left = getNextNodeAndDel(node.left, cur);
pushup(node);
return balance(node);
}
/*查询排名*/
static int getRankByKey(Node node, int key){
if(node==null) return 0;
if(key>node.key) return getSize(node.left) + node.cnt + getRankByKey(node.right, key);
if(key==node.key) return getSize(node.left) + 1;
return getRankByKey(node.left, key);
}
/*查询排名为 rank 的数值*/
static int getKeyByRank(Node node, int rank){
if(node==null) return 0;
if(rank<=getSize(node.left)) return getKeyByRank(node.left, rank);
if(rank<=getSize(node.left)+node.cnt) return node.key;
return getKeyByRank(node.right, rank-getSize(node.left)-node.cnt);
}
/*前驱(不同于前驱结点,x可能不在树中 )*/
static int getPre(Node node, int x){
if(node==null) return -INF;
if(x<=node.key) return getPre(node.left, x);
return Math.max(node.key, getPre(node.right, x));
}
/*后继*/
static int getNext(Node node, int x){
if(node==null) return INF;
if(x>=node.key) return getNext(node.right, x);
return Math.min(node.key, getNext(node.left, x));
}
static void build(){
root = new Node(-INF);
root.right = new Node(INF);
pushup(root);
}
static void order(Node node){
if(node==null) return;
order(node.left);
System.out.print(node.key+":"+getBalance(node)+" ");
order(node.right);
}
/*
1.插入数值 x。
2.删除数值 x(若有多个相同的数,应只删除一个)。
3.查询数值 x 的排名(若有多个相同的数,应输出最小的排名)。
4.查询排名为 x 的数值。
5.求数值 x 的前驱(前驱定义为小于 x 的最大的数)。
6.求数值 x 的后继(后继定义为大于 x 的最小的数)
*/
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
//n = 6;
build();
while(n-->0){
int opt, x;
opt = in.nextInt(); x = in.nextInt();
if(opt==1) root = insert(root, x);
else if(opt==2) root = remove(root, x);
else if(opt==3) System.out.println(getRankByKey(root, x)-1);
else if(opt==4) System.out.println(getKeyByRank(root, x+1));
else if(opt==5) System.out.println(getPre(root, x));
else System.out.println(getNext(root, x));
}
// order(root);
}
}