【NOI2004】【洛谷P1486】郁闷的出纳员(Splay写法)
平衡树简单题
因为是全局加减
维护一下全局一个表示当前工资加减情况
删除就把最低要求的后继到根
然后把左儿子删去就是了
因为个人代码是旋转了后继,为了保证有后继要先插入一个极大值
代码:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=100006;
char c[5];
int fa[N],son[N][2],rt,tot,n,add,mn,num,ans,siz[N],val[N],cnt[N];
#define lc(u) son[u][0]
#define rc(u) son[u][1]
inline void pushup(int u){
siz[u]=siz[lc(u)]+siz[rc(u)]+cnt[u];
}
inline void rotate(int v){
int u=fa[v],z=fa[u];
int t=(rc(u)==v);
son[z][rc(z)==u]=v;
fa[v]=z;
son[u][t]=son[v][t^1];
fa[son[v][t^1]]=u;
fa[u]=v,son[v][t^1]=u;
pushup(u),pushup(v);
}
inline void splay(int v,int goal){
while(fa[v]!=goal){
int u=fa[v],z=fa[u];
if(z!=goal)
(lc(z)==u)^(lc(u)==v)?rotate(v):rotate(u);
rotate(v);
}
if(!goal)rt=v;
}
inline void insert(int x){
int u=rt,f=0;
while(u&&val[u]!=x){
f=u,u=son[u][x>val[u]];
}
if(u)cnt[u]++;
else{
u=++tot;if(f)son[f][x>val[f]]=u;
fa[u]=f;val[u]=x,siz[u]=cnt[u]=1;
}
splay(u,0);
}
inline void find(int x){
int u=rt;
if(!u)return;
while(son[u][x>val[u]]&&val[u]!=x)
u=son[u][x>val[u]];
splay(u,0);
}
inline int nxt(int x){
find(x);
int u=rt;
if(val[u]>=x)return u;
u=rc(u);
while(lc(u))u=lc(u);
return u;
}
inline int kth(int k){
int u=rt;
if(siz[u]<k||k<=0)return -1;
while(224){
int v=lc(u);
if(siz[v]+cnt[u]<k){
k-=siz[v]+cnt[u];u=rc(u);
}
else{
if(siz[v]>=k)u=v;
else return val[u];
}
}
}
int main(){
n=read(),mn=read();insert(199999999);
for(int i=1;i<=n;i++){
scanf("%s",c);
int x=read();
if(c[0]=='I'){
if(x>=mn){
insert(x-add);num+=1;
}
}
else if(c[0]=='A'){
add+=x;
}
else if(c[0]=='S'){
add-=x;
int lv=nxt(mn-add);
splay(lv,0);
ans+=siz[lc(rt)];
num-=siz[lc(rt)];
cnt[lc(rt)]=siz[lc(rt)]=0,lc(rt)=0,siz[0]=0;
pushup(rt);
}
else{
int p=kth(num-x+1);
cout<<(p==-1?p:p+add)<<'\n';
}
//cout<<num<<'\n';
}
cout<<ans<<'\n';
}