题目
bzoj3224
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cstring>
using namespace std;
#define N 100005
int n,root,cnt,ch[N][2];//splay本质为二叉排序树
int fa[N],sz[N],w[N],num[N];//num记录出现次数
bool son(int x) {return ch[fa[x]][1]==x;}//判断是否为右儿子
void link(int x,int y,int f)//将y赋为x的f儿子
{
//回看rotate,y要放入位置原先可能本来就没有节点,在此处特判
if(x) ch[x][f]=y;
if(y) fa[y]=x;
}
void pushup(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+num[x];}
void rotate(int x,int &rt)//将x转至rt
{
int y=fa[x],z=fa[y],f=son(x);
link(z,x,son(y));//x y相对z的大小关系是相同的,将x置于y的位置
link(y,ch[x][f^1],f);//先看下一行,先将y要放的位置上原来的点接在y下方
link(x,y,f^1);//若x>y(f=1),则y<x(f=0),^,反之同理
//注意连接顺序,避免覆盖
if(y==rt) rt=x;
pushup(y);pushup(x);//y此时为x的子树,先更新
}
void splay(int x,int &rt)
{
while(x!=rt)//在x未转至rt时持续上移
{
int y=fa[x];
if(y!=rt) rotate(son(x)^son(y)? x:y,rt);//???
rotate(x,rt);
}
}
void insert(int &rt,int x,int last)//当前节点,需插入的值,父亲
{
if(!rt)
{
rt=++cnt;//加入新节点,需要取址
w[rt]=x;fa[rt]=last;sz[rt]=num[rt]=1;
splay(rt,root);//cxy:没事多转转
return;
}
sz[rt]++;
if(x==w[rt]) {num[rt]++;return;}
insert(ch[rt][w[rt]<x? 1:0],x,rt);
}
int findv(int rt,int x)//返回权值为v的节点第几小
{
if(w[rt]==x) return sz[ch[rt][0]]+1;
if(w[rt]>x) return findv(ch[rt][0],x);
return sz[ch[rt][0]]+num[rt]+findv(ch[rt][1],x);
}
int findk(int rt,int k)//返回第k大的节点下标
{
if(sz[ch[rt][0]]<k&&k<=sz[ch[rt][0]]+num[rt]) return rt;
if(sz[ch[rt][0]]>=k) return findk(ch[rt][0],k);
return findk(ch[rt][1],k-sz[ch[rt][0]]-num[rt]);
}
void del(int x)//删除权值为v的节点
{
int k=findv(root,x),t=findk(root,k);
splay(t,root);//将节点转至根
if(num[t]>1) {sz[t]--;num[t]--;return;}//若有多个直接删除
//这两句换一下就会挂,是因为转的次数比较少吗???
if(k==sz[root])//最大
{
root=ch[t][0];//直接换根
ch[t][0]=fa[t]=0;//清空
return;
}
if(k==1)//最小
{
root=ch[t][1];
ch[t][1]=fa[t]=0;
return;
}
int l=findk(root,k-1),r=findk(root,k+1);//前驱后继
splay(l,root);splay(r,ch[root][1]);//x必处于ch[r][0]
ch[r][0]=0;
pushup(r);pushup(l);
return;
}
int lower(int rt,int x)//查询v的前驱
{
if(!rt) return -1;//查询到空节点,返回-1
if(w[rt]>=x) return lower(ch[rt][0],x);
int t=lower(ch[rt][1],x);
return t==-1? rt:t;
}
int upper(int rt,int x)//查询v的后继
{
if(!rt) return -1;
if(w[rt]<=x) return upper(ch[rt][1],x);
int t=upper(ch[rt][0],x);
return t==-1? rt:t;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int opt,x;scanf("%d%d",&opt,&x);
if(opt==1) insert(root,x,0);
if(opt==2) del(x);
if(opt==3) printf("%d\n",findv(root,x));
if(opt==4) printf("%d\n",w[findk(root,x)]);
if(opt==5) printf("%d\n",w[lower(root,x)]);
if(opt==6) printf("%d\n",w[upper(root,x)]);
}
return 0;
}