蒟蒻的垂死挣扎
orz这题估计考场上想到也写不出来。
首先splay显然不是正解,考虑每次旋转对于树的影响,发现把min或max旋上去,树的形态几乎不变,手玩一下就可以知道这个规律,然后对于深度而言,min或max为根的子树深度不变,其他点深度+1即可,那么我们直观的想到用线段树维护深度信息,对于代价的计算就完成了。
然后考虑插点,明显不能按照题面去转,大力学一个 set ,然后就可以用set轻易地找到前驱及后继,这样我们就可以以一个极为舒服的姿势ac此题。
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#define RG register
#define N 200100
#define ls (now<<1)
#define rs ((now<<1)|1)
#define Ls s[x][0]
#define Rs s[x][1]
#define ll long long
#define ld long double
using namespace std;
inline int read(){
RG int x=0,o=1; RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*o;
}
int fa[N],s[N][2],m,tot,yyb[N],dep[N],root;
struct tree { int le,ri; int lz; } tr[N<<1];
struct mona { int op; int w; } ps[N];
inline void yyb_Orz(){
sort(yyb+1,yyb+tot+1);
RG int len=unique(yyb+1,yyb+1+tot)-yyb-1;
for(RG int i=1;i<=m;++i)
if(ps[i].op==1) ps[i].w=lower_bound(yyb+1,yyb+1+len,ps[i].w)-yyb;
}
inline void Pushlazy(RG int now,RG int w) { tr[now].lz+=w; }
inline void Pushdown(RG int now){
if(!tr[now].lz) return ;
Pushlazy(ls,tr[now].lz),Pushlazy(rs,tr[now].lz);
tr[now].lz=0;
}
inline void Build(RG int now,RG int le,RG int ri){
tr[now]=(tree) { le,ri };
if(le==ri) return ;
RG int mid=(le+ri)>>1;
Build(ls,le,mid),Build(rs,mid+1,ri);
}
inline void Update(RG int now,RG int le,RG int ri,RG int w){
if(tr[now].le==le&&tr[now].ri==ri){
Pushlazy(now,w); return ;
}Pushdown(now); RG int mid=(tr[now].le+tr[now].ri)>>1;
if(ri<=mid) Update(ls,le,ri,w);
else if(le>mid) Update(rs,le,ri,w);
else Update(ls,le,mid,w),Update(rs,mid+1,ri,w);
}
inline int Query(RG int now,RG int k){
if(tr[now].le==tr[now].ri) return tr[now].lz;
Pushdown(now);
RG int mid=(tr[now].le+tr[now].ri)>>1;
if(k<=mid) return Query(ls,k);
else return Query(rs,k);
}
inline void Setval(RG int k,RG int w){ RG int sum=Query(1,k); Update(1,k,k,w-sum); }
inline int Getval(RG int k) { return Query(1,k); }
set<int> S;
inline int Ins(RG int k,RG int op,RG int f){
s[f][op]=k,fa[k]=f; int sum=Getval(f);
Setval(k,sum+1),S.insert(k); return sum+1;
}
inline int Insert(RG int k){
if(!root) { root=k,S.insert(k),Setval(k,1); return 1; }
set<int>::iterator it;
it=S.begin(); if(k<*it) return Ins(k,0,*it);
it=S.end(),--it; if(k>*it) return Ins(k,1,*it);
it=S.lower_bound(k); if(!s[*it][0]) return Ins(k,0,*it);
--it; return Ins(k,1,*it);
}
inline int Splay_mmin(){
set<int>::iterator it=S.begin();
RG int sum=Getval(*it); if(root==*it) return 1;
Update(1,fa[*it],tot,1),Setval(*it,1);
if(s[*it][1]) fa[s[*it][1]]=fa[*it]; s[fa[*it]][0]=s[*it][1];
s[*it][1]=root,fa[*it]=0,fa[root]=*it,root=*it; return sum;
}
inline int Splay_mmax(){
set<int>::iterator it=S.end(); --it;
RG int sum=Getval(*it); if(root==*it) return 1;
Update(1,1,fa[*it],1),Setval(*it,1);
if(s[*it][0]) fa[s[*it][0]]=fa[*it]; s[fa[*it]][1]=s[*it][0];
s[*it][0]=root,fa[*it]=0,fa[root]=*it,root=*it; return sum;
}
inline int Del_mmin(){
RG int sum=Splay_mmin(); S.erase(root);
int las=root; root=s[root][1],s[las][1]=0,fa[root]=0;
Update(1,1,tot,-1); return sum;
}
inline int Del_mmax(){
RG int sum=Splay_mmax(); S.erase(root);
int las=root; root=s[root][0],s[las][0]=0,fa[root]=0;
Update(1,1,tot,-1); return sum;
}
int main(){
m=read();
for(RG int i=1;i<=m;++i){
ps[i].op=read();
if(ps[i].op==1) yyb[++tot]=ps[i].w=read();
} yyb_Orz(),Build(1,1,tot);
for(RG int i=1;i<=m;++i){
if(ps[i].op==1) printf("%d\n",Insert(ps[i].w));
if(ps[i].op==2) printf("%d\n",Splay_mmin());
if(ps[i].op==3) printf("%d\n",Splay_mmax());
if(ps[i].op==4) printf("%d\n",Del_mmin());
if(ps[i].op==5) printf("%d\n",Del_mmax());
} return 0;
}