P2286 [HNOI2004]宠物收养场

本文介绍了一种使用两棵平衡树实现宠物店模拟的方法,通过动态调整宠物和顾客的数量来模拟宠物店的运营情况。文章详细展示了平衡树的结构定义、插入、删除等操作,并给出完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

题目

思路

建2棵平衡树,一个存宠物,一个存顾客,然后看数量,随时切换就好了。
struct套struct是个好东西

code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
long long n,inf=0x7fffffff;
struct Treap{
	long long l,r;//左右子编号 
	long long v,d;//v权值(真),d随机值(旋转用) 
	long long cnt,size;//cnt重复个数,size子树大小 
};
struct f{
	Treap a[100010];
	long long tot,root=1,rank1,v;
	long long New()//新建节点 
	{
		a[++tot].v=v;
		a[tot].d=rand();
		a[tot].cnt=1;
		a[tot].size=1;
		return tot;
	}
	void Up(long long x)
	{
		a[x].size=a[a[x].l].size+a[a[x].r].size+a[x].cnt;
		return; 
	}
	void Build()
	{
		v=-inf;
		root=New();
		v=inf;
		a[root].r=New();
		//避免越界
		Up(root);
		return;
	}
	long long GRBV(long long x)//求排名 
	{
		if (x==0) return -2;//未查询到结果
		if (v==a[x].v) return a[a[x].l].size+1;//返回排名
		if (v<a[x].v) return GRBV(a[x].l); 
		return GRBV(a[x].r)+a[a[x].l].size+a[x].cnt;//类似二分 
	}
	long long GVBR(long long x)//求值 
	{
		if (x==0) return 0x7fffffff;//未查询到结果
		if (a[a[x].l].size>=rank1) return GVBR(a[x].l);//二分 
		if (a[a[x].l].size+a[x].cnt>=rank1) return a[x].v;//返回结果 
		rank1-=a[a[x].l].size+a[x].cnt;
		return GVBR(a[x].r);//二分 
	}
	void zig(long long &x)//右旋(左节点变父节点) 
	{
		long long y=a[x].l;
		a[x].l=a[y].r,a[y].r=x,x=y;
		Up(a[x].r),Up(x);
		return;
	}
	void zag(long long &x)//左旋(右节点变父节点) 
	{
		long long y=a[x].r;
		a[x].r=a[y].l,a[y].l=x,x=y;
		Up(a[x].l),Up(x);
		return;
	}
	void Insert(long long &x)//插入 
	{
		if (x==0)//新建节点 
		{
			x=New();
			return;
		}
		if (v==a[x].v)//已有节点,个数+1 
		{
			a[x].cnt++,Up(x);
			return;
		}
		if (v<a[x].v)//二分 
		{
			Insert(a[x].l);
			if (a[x].d<a[a[x].l].d) zig(x);
			Up(x);
			return;
		}
		Insert(a[x].r);
		if (a[x].d<a[a[x].r].d) zag(x);
		Up(x);
		return;
	}
	long long GP()//求前缀 
	{
		long long ans=0x7fffffff,x=root;
		while (x)
		{
			if (v>a[x].v)
			{
				ans=a[x].v,x=a[x].r;
			}
			else x=a[x].l;
		}
		return ans;
	}
	long long GN()//求后缀 
	{
		long long ans=0x7fffffff,x=root;
		while (x)
		{
			if (v<a[x].v)
			{
				ans=a[x].v,x=a[x].l;
			}
			else x=a[x].r;
		}
		return ans;
	}
	void Erase(long long &x)//删除 
	{
		if (x==0) return;
		if (v==a[x].v)
		{
			if (a[x].cnt>1)
			{
				a[x].cnt--,Up(x);
				return;//多个,删一个 
			}
			if (a[x].l||a[x].r)//有子节点
			{
				if (a[x].r==0||a[a[x].l].d>a[a[x].r].d) zig(x),Erase(a[x].r);
				else zag(x),Erase(a[x].l);//旋转,然后删除节点(保证平衡) 
				Up(x);
			}
			else x=0;
			return;
		}
		if (v<a[x].v)
		{
			Erase(a[x].l);
		}
		else
		{
			Erase(a[x].r);
		}//二分 
		Up(x);
		return;
	}
} a,b;
int main()
{
	srand(114514);
	a.Build();
	b.Build();
	cin>>n;
	long long o,x,ljh=0,lyw=0,s=0;
	while (n--)
	{
		cin>>o>>x;
		if (o==1)
		{
			if (ljh!=0)
			{
				ljh--;
				a.v=x+1;
				long long xx=a.GP();
				a.v-=2;
				long long yy=a.GN();
				if (abs(x-xx)<=abs(yy-x))
				{
					s=(s+abs(x-xx))%1000000;
					a.v=xx;
					a.Erase(a.root);
				}
				else
				{
					s=(s+abs(x-yy))%1000000;
					a.v=yy;
					a.Erase(a.root);
				}
			}
			else
			{
				lyw++;
				b.v=x;
				b.Insert(b.root);
			}
		}
		else
		{
			if (lyw!=0)
			{
				lyw--;
				b.v=x+1;
				long long xx=b.GP();
				b.v-=2;
				long long yy=b.GN();
				if (abs(x-xx)<abs(yy-x))
				{
					s=(s+abs(x-xx))%1000000;
					b.v=xx;
					b.Erase(b.root);
				}
				else
				{
					s=(s+abs(x-yy))%1000000;
					b.v=yy;
					b.Erase(b.root);
				}
			}
			else
			{
				ljh++;
				a.v=x;
				a.Insert(a.root);
			}
		}
	}
	cout<<s;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值