神仙东西
高级的呀,100多行,调了我亿点点时间。哦也,过了
直接放代码,代码有注释。
题目链接
#include<iostream>
#include<cstdio>
#include<cstdlib>
#define N 100000
#define INF 1000000000
using namespace std;
int n,opt,x;
int son[N+1][2],val[N+1],data[N+1],size[N+1],tot,cnt[N+1],root;
int born(int v)//新建节点,插入时用
{
val[++tot]=v;
data[tot]=rand();//随机化优先级
size[tot]=1;
cnt[tot]=1;
return tot;
}
void push_up(int id)//更新id点的子树大小
{ size[id]=size[son[id][0]]+size[son[id][1]]+cnt[id];}
void build()
{
root=born(-INF),son[root][1]=born(INF);//右子树比根节点大
push_up(root);//更新
}
void spin(int &id,int dir)
{
int temp=son[id][dir^1];
son[id][dir^1]=son[temp][dir];//将要旋转的根的左(右)儿子的右(左)儿子作为根的(左右)儿子
son[temp][dir]=id,id=temp;//将原根节点的左(右)儿子于原根节点连上,并作为新的根
push_up(son[id][dir]),push_up(id);
}
void ins(int &id,int v)
{
if(!id)
{
id=born(v);//此节点为空,直接插入
return;
}
if(v==val[id]) cnt[id]++;
else
{
int pd=v>val[id]?1:0;//看一下向哪里走
ins(son[id][pd],v);
if(data[son[id][pd]]>data[id]) spin(id,pd^1);
}
push_up(id);//更新一下本节点的信息
}
void del(int &id,int v)//删除函数
{
if(!id) return;//找不到,直接返回
if(v==val[id])//找到
{
if(cnt[id]>1) //副本大于一,那么直接减
{
cnt[id]--,push_up(id);
return;
}
if(son[id][1]||son[id][0])//如果不是的话要通过旋转把此节点放到最底下进行操作
{
if(!son[id][1]||data[son[id][1]]<data[son[id][0]]) spin(id,1),del(son[id][1],v);
else spin(id,0),del(son[id][0],v);
push_up(id);//时时刻刻记得更新
}
else id=0;//如果已经是叶子节点了,那就直接删
return;
}
v<val[id]?del(son[id][0],v):del(son[id][1],v);//看往哪走
push_up(id);
}
int get_rank(int id,int v)
{
if(!id) return -2;//就是说如果没有的话那么因为有INF,所以返回值会加一
if(v==val[id]) return size[son[id][0]]+1;
else if(v<val[id]) return get_rank(son[id][0],v);
else return size[son[id][0]]+cnt[id]+get_rank(son[id][1],v);
}
int get_val(int id,int rank)
{
if(!id) return INF;//好像根本没有这种样例qaq
if(rank<=size[son[id][0]]) return get_val(son[id][0],rank);
else if(rank<=size[son[id][0]]+cnt[id]) return val[id];
else return get_val(son[id][1],rank-cnt[id]-size[son[id][0]]);
}
int get_pre(int v)
{
int id=root,pre;
while(id)
{
if(val[id]<v) pre=val[id],id=son[id][1];
else id=son[id][0];
}
return pre;
}
int get_next(int v)//这好理解,两个相反。哈哈
{
int id=root,nxt;
while(id)
{
if(val[id]>v) nxt=val[id],id=son[id][0];
else id=son[id][1];
}
return nxt;
}
int qread()
{
int x=0,pd=1;
char c=getchar();
while(c>'9'||c<'0')
{
if(c=='-') pd=-1;
c=getchar();
}
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*pd;
}
void ks(int r)
{
if(r<0) putchar('-'),r=-r;//就不知道为什么有负数?(是我没看题了)
if(r>=10) ks(r/10);
putchar(r%10+'0');
}
int main()
{
n=qread();
build();
while(n--)
{
opt=qread(),x=qread();
if(opt==1) ins(root,x);
if(opt==2) del(root,x);
if(opt==3) ks(get_rank(root,x)-1),putchar('\n');//同下
if(opt==4) ks(get_val(root,x+1)),putchar('\n');//额,在树根有-INF
if(opt==5) ks(get_pre(x)),putchar('\n');
if(opt==6) ks(get_next(x)),putchar('\n');
}
return 0;
}