【题解】【bzoj 1503】【NOI2004】郁闷的出纳员

传送门

前置芝士

总体思路

首先,I 和 F 看起来比较清真,应该随便来个平衡树或者线段树之类的瞎维护一下就好。

主要是 A 和 S。

算法 1:

暴力加。

算法 2:

仿照线段树,打 Tag.

我们维护一个 Tag 变量和一个 minwage 变量。

别问我为什么是 wage,我也不知道。

I 操作的时候,要把给定的工资减去 Tag

F 操作的时候,找到之后加上 Tag 再输出即可。

A 操作的时候,设输入的第二个数为 delt,则 Tag+=delt,minwage-=delt; 即可。

S 操作同理 A,只不过要处理一下工资过低的人们大规模 sudo rm -rf / 加跑路的情况。

我们用无旋 treap 维护这个过程,除了大规模跑路的情况以外,所有操作都应该已经很简单了。

至于删除所有工资低于给定数的人,在无旋 treap 上其实也就很简单了,把整棵树 split 成两颗(无旋 treap 基本操作),然后乱搞一下就好了(见代码)。

事实上啰嗦这么半天感觉还不如直接上代码简单。

奇怪的点:立刻离开公司的人不计入最后一行的答案。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+9;
struct node{
	int val;
	int rnd;
	int l,r;
	int sz;
}tree[N];
int n;
int tot,root;
int Tag,leavetot;
int minwage; 
int newnode(int x){
	tree[++tot]=(node){x,rand(),0,0,1};
	return tot;
}
void pushup(int x){
	tree[x].sz=tree[tree[x].l].sz+tree[tree[x].r].sz+1;
}
void split(int now,int k,int&l,int&r){
	if(!now){
		l=r=0;
		return;
	}
	if(tree[now].val<=k){
		l=now;
		split(tree[now].r,k,tree[now].r,r);
	}
	else{
		r=now;
		split(tree[now].l,k,l,tree[now].l);
	}
	pushup(now);
}
int merge(int x,int y){
	if(!x)return y;
	if(!y)return x;
	if(tree[x].rnd<tree[y].rnd){
		tree[x].r=merge(tree[x].r,y);
		return pushup(x),x;
	}
	else{
		tree[y].l=merge(x,tree[y].l);
		return pushup(y),y;
	}
}
void insert(int val){
	int x,y;
	split(root,val,x,y);
	root=merge(merge(x,newnode(val)),y);
}
int getval(int rk,int pos=root){
	while(1){
		int v=tree[tree[pos].l].sz;
		if(rk==v+1)return tree[pos].val;
		else if(rk<=v)pos=tree[pos].l;
		else rk-=v+1,pos=tree[pos].r;
	}
}
signed main(){
	srand(time(0));
	cin>>n>>minwage;
	while(n--){
		char op;cin>>op;
		if(op=='I'){
			int wage;cin>>wage;
			wage-=Tag;
			if(wage>=minwage)insert(wage);
		}
		else if(op=='A'){
			int delt;cin>>delt;
			Tag+=delt,minwage-=delt;
		}
		else if(op=='S'){
			int delt;cin>>delt;
			Tag-=delt,minwage+=delt;
			int x,y;
			split(root,minwage-1,x,y);
			leavetot+=tree[x].sz;
			root=y;
		}
		else{
			int k;cin>>k;
			if(k>tree[root].sz)cout<<-1<<endl;
			else cout<<getval(tree[root].sz-k+1)+Tag<<endl;
		}
	}cout<<leavetot<<endl;
	return 0;
}

不懂的欢迎留言 AWA.

Over.

posted @ 2020-08-23 14:08  UnyieldingTrilobite  阅读(108)  评论(0编辑  收藏  举报