【洛谷P1486】郁闷的出纳员【Treap】

题目大意:

题目链接:https://www.luogu.org/problem/P1486
你需要维护一下四个操作:

  • I   k I\ k I k:插入一个数字 k k k
  • A   k A\ k A k:将所有数字增加 k k k
  • S   k S\ k S k:将所有数字减去 k k k
  • F   k F\ k F k:查询第 k k k大的数字。

注意如果一个数字小于 m i n min min,那么就要把这个数字删除。


思路:

依然算是一道 T r e a p Treap Treap的模板题,菜到已经只会敲模板了啊。
我们发现这里的修改操作全部都是对于所有数的,所以我们不用修改所有的数字,只要记录一个 s u m sum sum表示修改的值即可。
但是注意这样的话新加入的数字应该为 k − s u m k-sum ksum,因为我们定义每一个数字为 k + s u m k+sum k+sum,但是新加入的数字是不会被前面的修改操作影响的。所以减去 s u m sum sum之后,这个数字就是 ( k − s u m ) + s u m = k (k-sum)+sum=k (ksum)+sum=k
插入操作就是普通的插入操作。直接套模板就好了。
然后修改操作我们只需要把 s u m sum sum更改就行了。但是注意我们在进行 S S S操作时要考虑会影响到部分数字会被删除。
因为每一个数字都加上 s u m sum sum,那么对于数字 x x x,如果 x + s u m &lt; m i n x+sum&lt;min x+sum<min,那么 x x x就要被删除。也就是说, T r e a p Treap Treap中所有小于 m i n − s u m min-sum minsum的数字都要被删除。
由于修改操作很少,所以我们可以考虑暴力修改。先求出 v a l = m i n − s u m val=min-sum val=minsum的前驱,删除该前驱后再求 v a l ′ = p r e ( v a l ) val&#x27;=pre(val) val=pre(val),删除 v a l ′ val&#x27; val,以此类推,直到 v a l ≤ − ∞ val\leq -\infty val为止。
查询操作也是最基本的查询操作。但是注意查询的是第 k k k大,而不是第 k k k小。
总体来说还是很裸的,但是就是这样一道裸题都卡了我2天,不想说什么了。


代码:

#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=600010,Inf=2e9;
int n,minn,sum,root,tot,k,leave;
char ch;
bool flag;

struct treenode
{
	int lc,rc,dat,cnt,size,val;
};

struct Treap
{
	treenode t[N];
	
	int New(int val)
	{
		t[++tot].val=val;
		t[tot].dat=rand();
		t[tot].cnt=t[tot].size=1;
		return tot;
	}
	
	void update(int x)
	{
		t[x].size=t[t[x].lc].size+t[t[x].rc].size+t[x].cnt;
	}
	
	void build()
	{
		root=New(-Inf);
		t[1].rc=New(Inf);
		update(1);
	}
	
	void zig(int &x)
	{
		int y=t[x].lc;
		t[x].lc=t[y].rc; t[y].rc=x; x=y;
		update(t[x].rc); update(x);
	}
	
	void zag(int &x)
	{
		int y=t[x].rc;
		t[x].rc=t[y].lc; t[y].lc=x; x=y;
		update(t[x].lc); update(x);
	}
	
	void insert(int &x,int val)
	{
		if (!x)
		{
			x=New(val);
			return;
		}
		if (t[x].val==val)
		{
			t[x].cnt++;
			update(x);
			return;
		}
		if (val<t[x].val)
		{
			insert(t[x].lc,val);
			if (t[x].dat<t[t[x].lc].dat) zig(x);
		}
		else
		{
			insert(t[x].rc,val);
			if (t[x].dat<t[t[x].rc].dat) zag(x);
		}
		update(x);
	}
	
	void del(int &x,int val)
	{
		if (!x) return;
		if (t[x].val==val)
		{
			if (t[x].cnt>0)
			{
				leave+=t[x].cnt;
				t[x].cnt=0;
				//update(x);
			}
			if (t[x].lc || t[x].rc)
			{
				if (!t[x].lc || t[t[x].rc].dat>t[t[x].lc].dat)
					zag(x),del(t[x].lc,val);
				else
					zig(x),del(t[x].rc,val);
				update(x);
			}
			else x=0;
			return;
		}
		if (val<t[x].val) del(t[x].lc,val);
			else del(t[x].rc,val);
		update(x);
	}
	
	int get_val(int x,int rank)
	{
		if (!x)
		{
			flag=0;
			return Inf;
		}
		if (t[t[x].rc].size+1<=rank && t[t[x].rc].size+t[x].cnt>=rank)
			return t[x].val;
		if (rank<=t[t[x].rc].size) return get_val(t[x].rc,rank);
			else return get_val(t[x].lc,rank-t[t[x].rc].size-t[x].cnt);
	}
	
	int pre(int x,int val)
	{
		if (!x) return -Inf;
		if (t[x].val<val) return max(t[x].val,pre(t[x].rc,val));
			else return pre(t[x].lc,val);
	}
}Treap;

int main()
{
	scanf("%d%d",&n,&minn);
	srand(time(0));
	Treap.build();
	while (n--)
	{
		while (ch=getchar()) if (ch>='A'&&ch<='Z') break;
		scanf("%d",&k);
		if (ch=='I')
		{
			k-=sum;
			if (k+sum>=minn) Treap.insert(root,k);
		}
		if (ch=='A') sum+=k;
		if (ch=='S')
		{
			sum-=k;
			int val=Treap.pre(root,minn-sum);
			while (val>-Inf)
			{
				Treap.del(root,val);
				val=Treap.pre(root,val);
			}
		}
		if (ch=='F')
		{
			flag=1;
			int ans=Treap.get_val(root,k+1);
			if (!flag || ans<=-Inf) printf("-1\n");
				else printf("%d\n",ans+sum);
		}
	}
	printf("%d\n",leave);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值