【BZOJ1503】【NOI2004】郁闷的出纳员,Splay,调得我整个人都不好了。

题意注意:因为初始工资不足还没进入公司就愤愤离开的那些员工不算离开员工。

代码注意:延迟标记可以开一个全局变量比较好写,没有必要每个节点加一个add,然后pushdown。

没了,一点也不难写,题意一懂立刻AC ToT。

贴的代码略恶心,很多函数都是用不上的,有点小模板的感觉。(注释掉的del函数是错的。)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define N 1000005
#define inf 0x7fffffff
#define LL long long
#define is(x) (son[fa[x]][1]==x)
using namespace std;
/*
int digit[N];
*/
int ans,flag;
struct node
{
	int root,n,top,limit;
	int val[N],fa[N],son[N][2],size[N],num[N],snum[N];
//	int add[N],num[N];
//	long long sum[N],snum[N];
	inline void pushup(int x)
	{
		//size[x]=size[son[x][0]]+size[son[x][1]]+1;
		//sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x]*num[x];
		snum[x]=snum[son[x][0]]+snum[son[x][1]]+num[x];
	}
/*	inline void pushdown(int x)
	{
		if(add[x])
		{
			sum[x]+=snum[x]*add[x];
			val[x]+=add[x];
			add[son[x][0]]+=add[x];
			add[son[x][1]]+=add[x];
			add[x]=0;
		}
	}
	inline void Build(int l,int r,int mid)
	{根据序列建树
		if(l<mid)
		{
			int lmid=l+mid-1>>1;
			Build(l,mid-1,lmid);
			fa[lmid]=mid;
			son[mid][0]=lmid;
		}
		if(mid<r)
		{
			int rmid=mid+1+r>>1;
			Build(mid+1,r,rmid);
			fa[rmid]=mid;
			son[mid][1]=rmid;
		}
		val[mid]=digit[mid],pushup(mid);
	}
*/	inline void link(int x,int y,int d){son[y][d]=x;fa[x]=y;}
	inline void Rotate(int x)
	{
		int y=fa[x],z=fa[y],id=is(x),t=son[x][!id];
		if(t)fa[t]=y;son[y][id]=t;
		link(x,z,is(y));
		link(y,x,!id);
		pushup(y);
	}
	inline void Splay(int x,int k=0)
	{
		int y,z;
		while(fa[x]!=k)
		{
			y=fa[x];
			z=fa[y];
			if(z==k){Rotate(x);break;}
			if(is(x)==is(y))Rotate(y),Rotate(x);
			else Rotate(x),Rotate(x);
		}
		pushup(x);
		if(!k)root=x;
	}
	inline int getmin()
	{
		int x=root;
		while(son[x][0])x=son[x][0];
		return val[x];
	}
	inline int getmax()
	{
		int x=root;
		while(son[x][1])x=son[x][1];
		Splay(x);
		return val[x];
	}
	inline void findpred(int w)
	{
		int x=root;
		while(son[x][w>val[x]])
		{
			if(w==val[x])break;
			x=son[x][w>val[x]];
		}
		if(val[x]<w)Splay(root);
		else Splay(x);
	}
	inline bool find(int w,int k=0)
	{
		if(!n||getmax()<w||getmin()>w)return 0;
		int x=root;
		while(son[x][w>val[x]])
		{
			if(val[x]==w){Splay(x,k);return 1;}
			x=son[x][w>val[x]];
		}
		Splay(x,k);
		if(val[x]==w)return 1;
		return 0;
	}
	inline int Select(int rank,int k=0)
	{/*求第rank大的数,旋到k之下*/
		if(rank<=0||snum[root]<rank)return -1;
		int x=root;
		while(!(snum[son[x][0]]<rank&&rank<=snum[son[x][0]]+num[x]))
		{
			if(snum[son[x][0]]+1>rank)x=son[x][0];
			else rank=rank-snum[son[x][0]]-num[x],x=son[x][1];
		}
		Splay(x,k);
		return val[x];
	}
	inline void newnode(int &x,int y,int w)
	{
		x=++top;n++;
		son[x][0]=son[x][1]=0;
		val[x]=w;
		fa[x]=y;
		snum[x]=num[x]=size[x]=1;
	}
	void insert(int w,int k=0)
	{
		int x=root;
		while(son[x][w>val[x]])
		{
			if(w==val[x])
			{
				n++;
				num[x]++;
				snum[x]++;
				Splay(x,k);
				return ;
			}
			x=son[x][w>val[x]];
		}
		newnode(son[x][w>val[x]],x,w);
		Splay(son[x][w>val[x]]);
	}
	inline void del(int x,int y)
	{
		if(!x)return ;
		if(val[x]>=limit)del(son[x][0],x),pushup(x);
		else {
			int t=snum[son[x][0]]+num[x];
			ans+=t;n-=t;
			link(son[x][1],y,0);
			del(son[x][1],y);
		}
	}
/*	void del(int x,int y)
	{
		if(!x)return ;
		if(val[x]<limit)
		{
			ans+=snum[son[x][0]]+num[x];
			link(son[x][1],y,0);
			del(son[x][1],y);
		}
		else del(son[x][0],x);
		pushup(y);
	}
	inline void Insert(int x,int p)
	{//对于序列时的插入,x的后面插入一个新节点(可以改插一棵树)
		int l=Select(x,0),r=Select(x+1,l);
		newnode(son[r][0],r,p);
		Splay(n,0);
	}
	inline void ChangeS(int x,int p){x=Select(x,0),val[x]=p,Splay(x);}//把序列中第x个改成p
*/
}tree;
void handle()
{
	int i,j,k;
	int n,m;
	char a[5];
	scanf("%d%d",&n,&tree.limit);
	tree.newnode(tree.root,0,inf);
	for(i=1;i<=n;i++)
	{
		scanf("%s%d",a,&k);
		if(a[0]=='I'){
			if(k<tree.limit+flag);//ans++;
			else tree.insert(k-flag);
		}
		else if(a[0]=='A'){
			flag+=k;
			tree.limit-=k;
		}
		else if(a[0]=='S'){
			flag-=k;
			tree.limit+=k;
			tree.getmax();
			tree.del(tree.root,0);
		}
		else
		{
			j=tree.Select(tree.n-k);
			if(j==-1)puts("-1");
			else printf("%d\n",j+flag);
		}
	}
	printf("%d\n",ans);
}
int main()
{
	handle();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值