洛谷 P2286 HNOI2004 宠物收养场 解题报告

题目链接

很模板的一道 Treap,在基本的插入删除操作的前提下,只需支持寻找前驱和后继

在寻找前驱后继时,记得要考虑边界情况(就是没有前驱或后继)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<ctime>
using namespace std;
const long long Maxn=1000000+10,inf=(1ll<<60);
struct node{
	long long ls,rs,val,pri,cnt;
	#define ls(x) g[x].ls
	#define rs(x) g[x].rs
	#define v(x) g[x].val
	#define p(x) g[x].pri
	#define c(x) g[x].cnt
}g[Maxn];
long long n,root,ans;
long long tot,idcnt;
bool cur;
inline void zig(long long &x)
{
	long long y=ls(x);
	ls(x)=rs(y);
	rs(y)=x;
	x=y;
}
inline void zag(long long &x)
{
	long long y=rs(x);
	rs(x)=ls(y);
	ls(y)=x;
	x=y;
}
void ins(long long &x,const long long k)
{
	if(!x)
	{
		x=++idcnt,p(x)=((rand()<<8)+rand())%Maxn;
		v(x)=k,c(x)=1;
		return;
	}
	if(v(x)==k)
	{
		++c(x);
		return;
	}
	if(v(x)>k)
	{
		ins(ls(x),k);
		if(p(ls(x))<p(x))zig(x);
	}
	else
	{
		ins(rs(x),k);
		if(p(rs(x))<p(x))zag(x);
	}
}
void del(long long &x,const long long k) 
{
	if(v(x)==k)
	{
		if(c(x)>1){--c(x);return;}
		if(!ls(x) || !rs(x))x=ls(x)|rs(x);
		else if(p(ls(x))<p(rs(x)))zig(x),del(x,k);
		else zag(x),del(x,k);
		return;
	}
	if(v(x)>k)del(ls(x),k);
	else del(rs(x),k);
}
long long find_pre(const long long k)
{
	long long x=root,ret=0;
	while(x)
	{
		if(v(x)<=k)ret=v(x),x=rs(x);
		else x=ls(x);
	}
	return ret;
}
long long find_nxt(const long long k)
{
	long long x=root,ret=0;
	while(x)
	{
		if(v(x)>k)ret=v(x),x=ls(x);
		else x=rs(x);
	}
	return ret;
}
int main()
{
//	freopen("in.txt","r",stdin);
	srand(time(NULL));
	
	scanf("%lld",&n);
	ins(root,inf);
	ins(root,-inf);
	for(long long i=1;i<=n;++i)
	{
		long long opt,v;
		scanf("%lld%lld",&opt,&v);
		if(!tot)
		{
			cur=opt,++tot;
			ins(root,v);continue;
		}
		else if(opt==cur){ins(root,v),++tot;continue;}
		long long x=find_pre(v),y=find_nxt(v);
		ans=(ans+min(abs(x-v),abs(y-v)))%1000000;
		if(abs(x-v)<=abs(y-v))del(root,x);
		else del(root,y);
		--tot;
	}
	printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值