洛谷P5250 木材仓库

题目描述

博艾市有一个木材仓库,里面可以存储各种长度的木材,但是保证没有两个木材的长度是相同的。作为仓库负责人,你有时候会进货,有时候会出货,因此需要维护这个库存。有不超过 100000 条的操作:

  • 进货,格式1 Length:在仓库中放入一根长度为 Length(不超过 10^9109) 的木材。如果已经有相同长度的木材那么输出Already Exist
  • 出货,格式2 Length:从仓库中取出长度为 Length 的木材。如果没有刚好长度的木材,取出仓库中存在的和要求长度最接近的木材。如果有多根木材符合要求,取出比较短的一根。输出取出的木材长度。如果仓库是空的,输出Empty

输入格式

输出格式

输入输出样例

输入 #1复制

7
1 1
1 5
1 3
2 3
2 3
2 3
2 3

输出 #1复制

3
1
5
Empty

上代码:

#include<bits/stdc++.h>
using namespace std;

struct Node
{
	int val,key;
	int l,r;
	int size;
};
Node k[100001];
int n,root,Index;

inline void update(int x)//计算子树大小 
{
	k[x].size=k[k[x].l].size+k[k[x].r].size+1;
}

inline int newnode(int cnt)//新建结点 
{
	++Index;
	k[Index].val=cnt;
	k[Index].key=rand();
	k[Index].size=1;
	return Index;
}

void spilt(int now,int cnt,int &x,int &y)//分裂 
{
	if(!now) x=y=0;
	else
	{
		if(k[now].val<=cnt)
		{
			x=now;
			spilt(k[now].r,cnt,k[now].r,y);
		}
		else
		{
			y=now;
			spilt(k[now].l,cnt,x,k[now].l);
		}
		update(now);
	}
}

int merge(int x,int y)//合并 
{
	if(!x || !y) return x+y;
	else
	{
		if(k[x].key>k[y].key)
		{
			k[x].r=merge(k[x].r,y);
			update(x);
			return x;
		}
		else
		{
			k[y].l=merge(x,k[y].l);
			update(y);
			return y;
		}
	}
}

void Insert(int x)//插入 
{
	int a,b;
	spilt(root,k[x].val,a,b);
	root=merge(merge(a,x),b);
}

void Delete(int x)//删除 
{
	int a,b,c;
	spilt(root,x,a,c);
	spilt(a,x-1,a,b);
	b=merge(k[b].l,k[b].r);
	root=merge(merge(a,b),c);
}

void pre(int x,int &y)//x的前驱
{
	int a,b,now;
	spilt(root,x,a,b);
	now=a;
	while(k[now].r)
		now=k[now].r;
	y=now;
	root=merge(a,b);
}

void nxt(int x,int &y)//x的后继 
{
	int a,b,now;
	spilt(root,x-1,a,b);
	now=b;
	while(k[now].l)
		now=k[now].l;
	y=now;
	root=merge(a,b);
}

int main()
{
	int Alive=0;
	scanf("%d",&n);
	for(register int i=1;i<=n;++i)
	{
		int typ,a;
		scanf("%d%d",&typ,&a);
		if(typ==1)//进货操作 
		{
			int b;
			pre(a,b);
			if(a==k[b].val) printf("Already Exist\n");//如果树中已经有这个数了 
			else//如果树中还没有这个数 
			{
				Insert(newnode(a));//那么插入这个数 
				++Alive;//树中结点数 +1 
			}
		}
		if(typ==2)//出货操作 
		{
			int b,c;
			if(!Alive) printf("Empty\n");//如果树为空 
			else//如果树不为空 
			{
				int Ans;//要删除的数 
				pre(a,b);
				nxt(a,c);
				if(!b || !c)//如果一个数没有前驱或者没有后继 
				{
					if(!b) Ans=k[c].val;//如果没有前驱,删除后继 
					else Ans=k[b].val;//如果没有后继,删除前驱 
				}
				else//如果一个数前驱和后继都有了 
				{
					if(a-k[b].val<=k[c].val-a) Ans=k[b].val;
					else Ans=k[c].val;//比较前驱和后继与这个数的距离 
				}
				printf("%d\n",Ans);
				Delete(Ans);//删除这个数 
				--Alive;//树中结点数 -1  
			}
		}
	}
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值