#include<cstdio>
using namespace std;
int n,op,x,root,t,l;
struct dian
{
int left,right,leftnum,rightnum,value;
dian():left(-1),right(-1),leftnum(0),rightnum(0),value(-1) {}
};
struct dian d[10007];
int c1(int x)//如果小于根节点值,则往左走,无其他改变;若大于根节点值,则往右走,且用累加器累加左子树大小+1(根节点)记录排名;若等于,则累加器值即为所求
{
struct dian dd;
dd.value=x;
int roo=root,sum=0;
while(1)
{
if(x<d[roo].value)
if(d[roo].left!=-1)
roo=d[roo].left;
else
return -2147483647;
else if(x>d[roo].value)
{
sum+=1+d[roo].leftnum;
if(d[roo].right!=-1)
roo=d[roo].right;
else
return -2147483647;
}
else
return sum+d[roo].leftnum+1;
}
}
int c2(int x)//如果左子树大小+1大于要找的名次,说明要找的在左子树,即在左子树中去找排X的;若小于,说明在右子树中,是在右子树中找名次为x-左子树大小-1(根节点)的;若等于,则返回此节点的value值就好
{
if(x<=0||x>l)
return -2147483647;
int roo=root,sum;
while(1)
{//printf("t2\n");
sum=d[roo].leftnum;
if(x<sum+1)
roo=d[roo].left;
else if(x>sum+1)
{
x-=d[roo].leftnum+1;
roo=d[roo].right;
}
else if(x==sum+1)
return d[roo].value;
}
}
inline int c3(int x)//c3c4应该有两种写法的,按书上说的需要先找到排名再推节点,应该是o(2logn),但如果我直接找节点,再直接找左右子树,应该只有o(logn),大概会更快?这个思路不通,因为前驱和后继不一定就是左右子结点,比如后继可能会是左子节点的右子结点
{
int cc=c1(x);
if(cc!=-2147483647)
return c2(cc-1);
else
return cc;
}
inline int c4(int x)
{
int cc=c1(x);
if(cc!=-2147483647)
return c2(cc+1);
else
return 2147483647;
}
void c5(int x)
{
struct dian dd;
dd.value=x;
int roo=root;
if(!l)
{
d[l++]=dd;
return;
}
while(1)
{
if(x<d[roo].value)
{
d[roo].leftnum++;
if(d[roo].left==-1)
{
d[roo].left=l;
d[l++]=dd;
return;
}
else
roo=d[roo].left;
}
else if(x>d[roo].value)
{
d[roo].rightnum++;
if(d[roo].right==-1)
{
d[roo].right=l;
d[l++]=dd;
return;
}
else
roo=d[roo].right;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d%d",&op,&x);
if(op==5)
c5(x);
else if(op==4)
printf("%d\n",c4(x));
else if(op==3)
printf("%d\n",c3(x));
else if(op==2)
printf("%d\n",c2(x));
else if(op==1)
printf("%d\n",c1(x));
}
//for(int i=0;i<l;i++)printf("\n序列%d 左子树数量为%d 右子树数量为%d 左子节点为%d 右子结点为%d",d[i].value,d[i].leftnum,d[i].rightnum,d[i].left,d[i].right);
return 0;
}