BZOJ 1503: [NOI2004]郁闷的出纳员

题目地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1503


题目大意:实现5个操作:建立新档案、全局加、全局减、查询K大,当工资低于下界时离开公司。


算法讨论:

        下传标记的平衡树,我用的是Treap。

        对于“当工资低于下界时离开公司“操作,只需要在查询操作的基础上加一些判断即可。

        其余操作和Treap相同。

        一题就这样水水地A出了。


Code:

/*
 * Problem:1503
 * Author:PYC
 */

#include <cstdio>
#include <cstdlib>

#define maxn 100000
#define ll(x) (tree[tree[(x)].l].sz)
#define rr(x) (tree[tree[(x)].r].sz)

using namespace std;

int n,m,tot,root,in;

struct node{
	int key,val,l,r,sz,aux,add;
}tree[maxn+1];

void up(int rt){
	tree[rt].sz=(tree[rt].l?ll(rt):0)+(tree[rt].r?rr(rt):0)+tree[rt].val;
}

void down(int rt){
	if (tree[rt].add){
		tree[tree[rt].l].add+=tree[rt].add;
		tree[tree[rt].r].add+=tree[rt].add;
		tree[tree[rt].l].key+=tree[rt].add;
		tree[tree[rt].r].key+=tree[rt].add;
		tree[rt].add=0;
	}
}

void zig(int &rt){
	int t=tree[rt].l;
	tree[rt].l=tree[t].r;
	tree[t].r=rt;
	up(rt);
	up(t);
	rt=t;
}

void zag(int &rt){
	int t=tree[rt].r;
	tree[rt].r=tree[t].l;
	tree[t].l=rt;
	up(rt);
	up(t);
	rt=t;
}

void insert(int &rt,int y){
	if (!rt){
		rt=++tot;
		tree[rt].key=y;
		tree[rt].aux=rand()*rand();
		tree[rt].val=tree[rt].sz=1;
		tree[rt].l=tree[rt].r=0;
		return;
	}
	down(rt);
	if (y==tree[rt].key){
		tree[rt].val++;
		tree[rt].sz++;
		return;
	}
	if (y<tree[rt].key){
		insert(tree[rt].l,y);
		tree[rt].sz++;
		if (tree[rt].aux>tree[tree[rt].l].aux) zig(rt);
		return;
	}
	if (y>tree[rt].key){
		insert(tree[rt].r,y);
		tree[rt].sz++;
		if (tree[rt].aux>tree[tree[rt].r].aux) zag(rt);
		return;
	}
}

void find(int &rt){
	if (!rt) return;
	down(rt);
	if (tree[rt].key<m){
		rt=tree[rt].r;
		find(rt);
		return;
	}
	if (tree[rt].key>=m){
		find(tree[rt].l);
		up(rt);
		return;
	}
}

int kth(int &rt,int y){
	if (!rt) return 0;
	down(rt);
	if (y>=rr(rt)+1 && y<=rr(rt)+tree[rt].val) return tree[rt].key;
	if (y<rr(rt)+1) return kth(tree[rt].r,y);
	if (y>rr(rt)+tree[rt].val) return kth(tree[rt].l,y-rr(rt)-tree[rt].val);
}

int main(){
	srand(0);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i){
		char ch=getchar();
		while (ch!='I' && ch!='A' && ch!='S' && ch!='F') ch=getchar();
		int y;
		scanf("%d",&y);
		if (ch=='I'){
			if (y>=m){
				insert(root,y);
				in++;
			}
			continue;
		}
		if (ch=='A'){
			tree[root].key+=y;
			tree[root].add+=y;
			continue;
		}
		if (ch=='S'){
			tree[root].key-=y;
			tree[root].add-=y;
			find(root);
			continue;
		}
		if (ch=='F'){
			if (y>tree[root].sz) printf("-1\n");
			else printf("%d\n",kth(root,y));
			continue;
		}
	}
	printf("%d\n",in-tree[root].sz);
	return 0;
}

By Charlie Pan

Mar 4,2014

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值