1. 程式人生 > 實用技巧 >#Splay#洛谷 1486 [NOI2004]鬱悶的出納員

#Splay#洛谷 1486 [NOI2004]鬱悶的出納員

題目


分析

考慮加減工資直接打標記,查詢第\(k\)多可以用平衡樹,
刪除有點噁心,這裡考慮Splay,將需要刪除的部分的後繼splay到根節點並將左子樹斷邊


程式碼

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int inf=0x7fffffff,N=2000011;
int n,mn,delta,ans;
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
inline void print(int ans){
	if (ans<0) putchar('-'),ans=-ans;
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
struct Splay{
	int siz[N],cnt[N],son[N][2],fat[N],w[N],root,tot;
	inline void pup(int x){siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x];}
	inline bool Is_R(int x){return son[fat[x]][1]==x;}
    inline void rotate(int x){
    	rr int Fa=fat[x],FFa=fat[Fa],wh=Is_R(x);
    	son[FFa][Is_R(Fa)]=x,fat[x]=FFa,son[Fa][wh]=son[x][wh^1],
    	fat[son[x][wh^1]]=Fa,son[x][wh^1]=Fa,fat[Fa]=x,pup(Fa),pup(x);
	}
	inline void splay(int x,int tar){
		for (;fat[x]!=tar;rotate(x)){
			rr int Fa=fat[x],FFa=fat[Fa];
			if (FFa!=tar) rotate((Is_R(x)^Is_R(Fa))?x:Fa);
		}
		if (!tar) root=x;
	}
    inline void Insert(int x){
    	rr int now=root,Fa=0;
    	while (now&&w[now]!=x)
    	    Fa=now,now=son[now][x>w[now]];
    	if (now) ++cnt[now];
    	else{
    		now=++tot;
    		if (Fa) son[Fa][x>w[Fa]]=now;
    		son[now][0]=son[now][1]=0,fat[now]=Fa,
			w[now]=x,cnt[now]=siz[now]=1;
		}
		splay(now,0);
	}
	inline void Fsplay(int x){
		rr int now=root;
		if (!now) return;
		while (son[now][x>w[now]]&&x!=w[now])
		    now=son[now][x>w[now]];
		splay(now,0);
	}
	inline signed pre(int x){
		Fsplay(x);
		rr int now=root;
		if (w[now]<x) return now;
		now=son[now][0];
		while (son[now][1]) now=son[now][1];
		return now;
	}
	inline signed suf(int x){
		Fsplay(x);
		rr int now=root;
		if (w[now]>x) return now;
		now=son[now][1];
		while (son[now][0]) now=son[now][0];
		return now;
	}
    inline signed Delete(int x){
    	rr int L=1,R=suf(x);
    	splay(L,0),splay(R,L);
    	rr int ans=siz[son[R][0]];
		son[R][0]=0,pup(R),pup(L);
		return ans;
	}
	inline signed kth(int rk){
		rr int now=root;
		if (siz[now]<rk) return -1;
		while (1){
			rr int lson=son[now][0];
			if (siz[lson]+cnt[now]<rk)
				rk-=siz[lson]+cnt[now],now=son[now][1];
				else if (rk<=siz[lson]) now=son[now][0];
				    else break;
		}
		splay(now,0);
		return w[now];
	}
	inline void BUILD(){Insert(-inf),Insert(inf);}
}Tre;
signed main(){
	n=iut(),mn=iut(),Tre.BUILD();
	for (rr int i=1;i<=n;++i){
		rr char c=getchar();
		while (!isalpha(c)) c=getchar();
		switch (c){
			case 'I':{
				rr int x=iut();
				if (x>=mn) Tre.Insert(x-delta); 
				break;
			}
			case 'A':{
				delta+=iut();
				break;
			}
			case 'S':{
				delta-=iut();
				ans+=Tre.Delete(mn-delta-1);
				break;
			}
			case 'F':{
				rr int x=iut(),SIZ=Tre.siz[Tre.root];
				if (SIZ-2>=x) print(Tre.kth(SIZ-x)+delta);
				    else print(-1);
				putchar(10); 
				break;
			}
		}
	}
	return !printf("%d",ans);
}