[BZOJ1503][NOI2004]郁闷的出纳员(平衡树splay)

题目:

我是超链接

题解:

那什么.....今天真是有毒,splay都是细节没有考虑好,如果这个人本来就达不到minn,何必让他加入公司呢......

没有写区间操作,直接把minn处理了,好像简单一些呢

代码:

#include <cstdio>
#define N 100000
using namespace std;
int f[N+5],cnt[N+5],size[N+5],ch[N+5][2],key[N+5];
int sz=0,root=0,ff=0,e=0,tot;
void clear(int x){size[x]=cnt[x]=key[x]=f[x]=0;ch[x][0]=ch[x][1]=0;}
int get(int x){return ch[f[x]][1]==x;}
int pre()
{
	int now=ch[root][0];
	while (ch[now][1]) now=ch[now][1];
	return now;
}
int next()
{
	int now=ch[root][1];
	while (ch[now][0]) now=ch[now][0];
	return now;
}
void updata(int x)
{
	if (x)
	{
		size[x]=cnt[x];
		if (ch[x][0]) size[x]+=size[ch[x][0]];
		if (ch[x][1]) size[x]+=size[ch[x][1]];
	}
}
void rotate(int x) {
	int old=f[x],oldf=f[old],which=get(x);
	ch[old][which]=ch[x][which^1];
	f[ch[x][which^1]]=old;
	ch[x][which^1]=old;
	f[old]=x;
	f[x]=oldf;
	if (oldf) ch[oldf][ch[oldf][1]==old]=x;
	updata(old);
	updata(x);
}
void splay(int x)
{
	for (int fa;fa=f[x];rotate(x))
	  if (f[fa])
	    rotate((get(x)==get(fa))?fa:x);
	root=x;
}
int findx(int x)
{
	int now=root;
	while (1)
	{
		if(ch[now][0] && x<=size[ch[now][0]])
		  now=ch[now][0];
		else
		{
			int tmp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
			if (x<=tmp) return key[now];
			x-=tmp; now=ch[now][1];
		}
	} 
}
int find(int x)
{
	int ans=0,now=root;
	while (1)
	{
		if (x<key[now])
		  now=ch[now][0];
		else
		{
			ans+=(ch[now][0]?size[ch[now][0]]:0);
			if (x==key[now])
			{
				splay(now); return ans+1;
			}
			ans+=cnt[now];
			now=ch[now][1];
		}
	}
}
void insert(int x)
{
	if (root==0)
	{
		sz++;root=sz;size[sz]=cnt[sz]=1;key[sz]=x;f[sz]=0;ch[sz][0]=ch[sz][1]=0;return;
	}
	int now=root,fa=0;
	while (1)
	{
		if (x==key[now])
		  {
		  	cnt[now]++; updata(now); updata(fa); splay(now); return;
		  }
		fa=now;
		now=ch[now][key[now]<x];
		if (now==0)
		{
			sz++;
			size[sz]=cnt[sz]=1;key[sz]=x;f[sz]=fa;ch[sz][0]=ch[sz][1]=0;
			ch[fa][key[fa]<x]=sz;
			updata(fa);
			splay(sz);
			return;
		}
	}
}
void del(int x)
{
	int whatever=find(x);
	if (cnt[root]>1) 
	{
		cnt[root]--; updata(root); return;
	}
	if (!ch[root][0] && !ch[root][1]) {
		clear(root); root=0; return;
	}
	if (!ch[root][0])
	{
		int oldroot=root; root=ch[root][1]; f[root]=0; clear(oldroot); return;
	}
	else if (!ch[root][1])
	{
		int oldroot=root; root=ch[root][0]; f[root]=0; clear(oldroot); return;
	}
	int leftbig=pre(),oldroot=root;
	splay(leftbig);
	f[ch[oldroot][1]]=root;
	ch[root][1]=ch[oldroot][1];
	clear(oldroot);
	updata(root);
	return;
}
int main()
{
	int n,minn,i;
	scanf("%d%d",&n,&minn);
	for (i=1;i<=n;i++)
	{
		char chh;int x;
		scanf("\n%c%d",&chh,&x);
		switch(chh)
		{
			case 'I':if (x<minn) continue; insert(x-e); tot++; break;
			case 'A':e+=x; break;
			case 'S':e-=x; insert(minn-e); ff+=size[ch[root][0]]; ch[root][0]=0; del(minn-e); break;
			case 'F':if (tot-ff<x) printf("-1\n");else printf("%d\n",findx(tot-ff-x+1)+e); break;
		}
	}  
	printf("%d",ff);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值