[noi 2004] 郁闷的出纳员

原题地址


 花了一两天真正的熟悉了Treap,对于一个东西,本蒟蒻认为,不应该要会,还应会熟练的写,【像哈狗写这个只需十分钟】


好吧,话归正题 先推荐另类解法 戳进去  


此题解法很多BIT , 权值线段树 ,各种平衡树(准备抽空写)。。。。 是一道很棒的模板题。


这道题我们把每次全体加的工资和减的弄到一个变量,姑且叫为w,把当前操作的数叫为k,当我们加工资时,肯定不会有员工退役把。。。所以直接将w 加上 k就行了

如果是减工资,就有可能有员工退役了,我们就应进行一次删除操作了。。。

那么如何删除呢?

先把w减去k,然后遍历。

我们遇到的节点的值 + w 如果大于等于工资下限的话,那么肯定只有可能左儿子中有小于工资下限的吧,那么就跑到它左儿子那里去。如果遇到节点的值是小于工资下限的,那么它右子树有可能有小于工资下限的,那么就一直左旋(这样就能不断地把大的旋上来),直到右节点的值是Null或当前节点的值是大于等于工资上限的,然后删除左儿子(子树)( 即把左边变为Null),如果当前节点也是小于工资上限的话也把当前节点赋为Null。。

至于加入新的节点的话,前面的w跟他毛关系不沾对吧,就把他的值减去w就行啦!


#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<map>

const int N = 1e5 + 7;

#define R12() ((rand()<<12) + (rand()<<7) + rand())
#define R233() (R12() % 4454515 + R12() % 45444211 + R12() % 144521 + 1)

int Q,min1,w;

class Treap {
	private :
		struct Node {
			Node* son[2];
			int size,num,data,hr;
			Node () {}
			Node (int data,Node *fl) : data(data) { son[0] = son[1] = fl; size = num = 1; hr = R233(); }
			void update () { size = son[0] -> size + son[1] -> size + num; }
		}*Null,*root,meme[N],*pool;
		
		int ball,money;
	
		void rotate (Node *&T,bool v) {
			Node* Tt = T -> son[v];
			T -> son[v] = Tt -> son[v^1];
			Tt -> son[v^1] = T;
			T -> update(); Tt -> update();
			T = Tt;
		}
		
		void Delete (Node *&T) {
			if(T == Null) return ;
			while (T -> son[1] != Null && T -> data + money <= min1) T -> son[0] = Null , rotate (T , 1);
			if(T -> data + money <= min1) {
				if(T -> data + money < min1) T = Null;
				else T -> son[0] = Null , T -> size = T -> num;
				return;	
			}
			Delete (T -> son[0]);
			T -> update();
		}
		
		void Insert (Node *&T) {
			if(T == Null) { T = new (pool++) Node (ball,Null); return ; }
			if(T -> data == ball) { ++ T -> num; ++ T -> size; return ; }
			bool v = T -> data < ball;
			Insert(T -> son[v]);
			if(T -> hr < T -> son[v] -> hr) rotate (T , v);
			else T -> update();
		}
	
		int Rank (Node *&T) {
			if(T == Null) return -1;
			if(T -> son[1] -> size >= ball) return Rank (T -> son[1]);
			if(T -> son[1] -> size + T -> num >= ball) return T -> data;
			ball -= T -> son[1] -> size + T -> num; return Rank (T -> son[0]);
		}
	
	public :
		Treap () { Null = new Node(); Null -> size = Null -> num = 0; }
		void clear() { root = Null; pool = meme; money = 0; }
		void Ins (int xxx) { ball = xxx - money; Insert(root); }
		void Rai (int xxx) { money += xxx; }
		void Cut (int xxx) { money -= xxx; Delete(root); }
		int Ran (int xxx) { ball = xxx; int k = Rank(root); return k == -1 ? -1 : k + money; }
		int size () { return root -> size; }
}treap;

int ans;
char opt[10];

int main () {
	scanf("%d%d",&Q,&min1);
	treap.clear();
	while (Q--) {
		scanf("%s%d",opt,&w);
		if(opt[0] == 'I' && w >= min1) {
			treap.Ins(w);
			++ans;
		}
		if(opt[0] == 'A') treap.Rai(w);
		if(opt[0] == 'S') treap.Cut(w);
		if(opt[0] == 'F') printf("%d\n",treap.Ran(w));
	}
	printf("%d\n",ans - treap . size());
	return 0;
}



that is all.Thank you for watching.

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值