[bzoj1503][NOI2004]郁闷的出纳员

本题依然是一道数据结构题,对本题而言,依然可以用splay来解。

本题的一个难点(对于我这个弱菜而言)是如何动态的改变平衡树中的值。其实我们可以借鉴线段树中的lazy tag的思想,因为若要变动则是整棵树一起变,所以我们可以开设一个全局变量delta表示此时对整棵树的改变值,这样一来,在每次插入节点x时,我们把x-delta插入平衡树中(想想这是为什么,不难),然后检查时若此时的节点y满足y+delta<min则说明工资低于最低值,删除这个点和其左子树。

最后就是要注意细节,首先在插入时可能一开始工资就低于min,此时是不需要把他算入离开公司员工数的。还有就是删除时,要找到真正的第一个y+delta<min的值。

program chashier;
const
	MAXN=100000;
type
	date=record
		ch:array[0..1]of longint;
		v,f,sz:longint;
	end;
var
	n,min,i,top,sum,root,delta,tst,x:longint;c:char;
	st:array[1..MAXN]of longint;
	t:array[0..MAXN+10]of date;
procedure newnode(var x:longint;f,k:longint);
begin
	if(tst<>0)then begin x:=st[tst];dec(tst) end
	else begin inc(top);x:=top; end;
	t[x].ch[0]:=0;t[x].ch[1]:=0;t[x].v:=k;t[x].f:=f;t[x].sz:=1;
end;
function cmp(x,k:longint):longint;
begin
	if(t[x].ch[0]=k)then exit(0) else exit(1);
end;
procedure pushup(k:longint);
begin
	t[k].sz:=1+t[t[k].ch[1]].sz+t[t[k].ch[0]].sz;
end;
procedure rotate(k,c:longint);
var i:longint;
begin
	i:=t[k].f;
	t[i].ch[c xor 1]:=t[k].ch[c];t[t[k].ch[c]].f:=i;t[k].ch[c]:=i;
	t[k].f:=t[i].f;
	if(t[i].f<>0)then t[t[i].f].ch[cmp(t[i].f,i)]:=k;
	t[i].f:=k;
	pushup(i);
end;
procedure splay(k,goal:longint);
var x,y,f1,f2:longint;
begin
	while(t[k].f<>goal)do
	begin
		x:=t[k].f;y:=t[x].f;
		if(y=goal)then rotate(k,cmp(x,k)xor 1)
		else begin
			f1:=cmp(y,x);f2:=cmp(x,k);
			if(f1=f2)then begin rotate(x,f1 xor 1);rotate(k,f1 xor 1) end
			else begin rotate(k,f2 xor 1);rotate(k,f1 xor 1) end;
		end;
	end;
	pushup(k);
	if(goal=0)then root:=k;
end;
procedure insert(k:longint);
var i,j,x:longint;
begin
	if(root=0)then
	begin
		newnode(root,0,k);exit;
	end;
	j:=0;i:=root;
	repeat
		j:=i;
		if(k<t[i].v)then i:=t[i].ch[0] else i:=t[i].ch[1];
	until i=0;
	if(k<t[j].v)then x:=0 else x:=1;
	newnode(t[j].ch[x],j,k);
	splay(t[j].ch[x],0);
end;
function find(k:longint):longint;
var i:longint;
begin
	i:=root;
	while(t[t[i].ch[1]].sz<>k)do
	begin
		if(k<t[t[i].ch[1]].sz)then i:=t[i].ch[1]
		else begin
			k:=k-t[t[i].ch[1]].sz-1;i:=t[i].ch[0];
		end;
	end;
	splay(i,0);
	exit(t[i].v+delta);
end;
procedure del(k:longint);
begin
	if(k=0)then exit;
	inc(sum);inc(tst);st[tst]:=k;
	del(t[k].ch[0]);del(t[k].ch[1])
end;
function found(k:longint):longint;
var i:longint;
begin
	if(k=0)then exit(0);
	if(t[k].v+delta<min)then
	begin
		i:=found(t[k].ch[1]);
		if(i=0)then exit(k) else exit(i);
	end;
	exit(found(t[k].ch[0]));
end;
procedure update;
var x:longint;
begin
	x:=found(root);
	if(x<>0)then
	begin
		splay(x,0);
		if(t[x].ch[1]=0)then
		begin
			delta:=0;root:=0;del(x);
		end
		else begin
			root:=t[root].ch[1];t[root].f:=0;t[x].ch[1]:=0;
			del(x);
		end;
	end;
end;
procedure init;
begin
	sum:=0;delta:=0;tst:=0;top:=0;root:=0;
end;
begin
	readln(n,min);
	init;
	for i:=1 to n do
	begin
		readln(c,x);
		if(c='S')and(root<>0)then begin delta:=delta-x;update; end;
		if(c='A')and(root<>0)then delta:=delta+x;
		if(c='I')and(x>=min)then insert(x-delta);
		if(c='F')then
		begin
			if(t[root].sz<x)then writeln(-1) else writeln(find(x-1));
		end;
	end;
	writeln(sum);
end.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值