[BZOJ1208][HNOI2004]宠物收养所(平衡树splay)

本文详细介绍了Splay树的基本操作及实现代码,包括插入、删除、查找等关键操作,并特别强调了在没有前驱或后继节点时的操作细节。

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

题目:

我是超链接

题解:

除了板子第一发splay,挺裸的,就是要注意没有前驱的时候必须选后继,没有后继的时候必须选前驱!

代码:

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define N 80000
#define Mod 1000000
using namespace std;
int f[N+5],cnt[N+5],size[N+5],ch[N+5][2],key[N+5];
int sz=0,root=0;
bool fff=0;
void clear(int x) {
	f[x]=cnt[x]=size[x]=ch[x][0]=ch[x][1]=key[x]=0;
}
int get(int x) {
	return ch[f[x]][1]==x;
}
void updata(int x) {
	if (x) {
		size[x]=cnt[x];
		if (ch[x][0]) size[x]+=size[ch[x][0]];
		if (ch[x][1]) size[x]+=size[ch[x][1]];
	}
}
void rotate(int x) {
	int old=f[x],oldf=f[old],which=get(x);
	ch[old][which]=ch[x][which^1];
	f[ch[x][which^1]]=old;
	ch[x][which^1]=old;
	f[old]=x;
	f[x]=oldf;
	if (oldf) ch[oldf][ch[oldf][1]==old]=x;
	updata(old);
	updata(x);
}
void splay(int x) {
	for (int fa; fa=f[x]; rotate(x))
		if (f[fa])
			rotate((get(x)==get(fa)?fa:x));
	root=x;
}
int pre() {
	int now=ch[root][0];
	while (ch[now][1]) now=ch[now][1];
	return now;
}
int next() {
	int now=ch[root][1];
	while (ch[now][0]) now=ch[now][0];
	return now;
}
int find(int x) 
{
	int ans=0,now=root;
	while (1)
	{
		if (now==0) return 0;
		if (x<key[now])
		  now=ch[now][0];
		else
		  {
		  	if (x==key[now])
		  	{
		  		splay(now);
		  		return true;
			  }
		  	now=ch[now][1];
		  } 
	}
}
void insert(int x) {
	if (root==0) {
		++sz;
		f[sz]=0;
		key[sz]=x;
		root=sz;
		size[sz]=cnt[sz]=1;
		ch[sz][0]=ch[sz][1]=0;
		return;
	}
	int now=root,fa=0;
	while (1) {
		if (x==key[now]) {
			cnt[now]++;
			updata(now);
			updata(fa);
			splay(now);
			return;
		}
		fa=now;
		now=ch[now][key[now]<x];
		if(now==0) {
			sz++;
			f[sz]=fa;
			ch[sz][0]=ch[sz][1]=0;
			key[sz]=x;
			size[sz]=cnt[sz]=1;
			ch[fa][key[fa]<x]=sz;
			updata(fa);
			splay(sz);
			break;
		}
	}
}
void del(int x) {
	int h=find(x);
	if (cnt[root]>1) {
		cnt[root]--;
		updata(root);
		return;
	}
	if (!ch[root][0] && !ch[root][1]) {
		clear(root);
		root=0;
		return;
	}
	if (!ch[root][0]) {
		int oldroot=root;
		root=ch[root][1];
		f[root]=0;
		clear(oldroot);
		return;
	} else if (!ch[root][1]) {
		int oldroot=root;
		root=ch[root][0];
		f[root]=0;
		clear(oldroot);
		return;
	}
	int leftbig=pre(),oldroot=root;
	splay(leftbig);
	ch[root][1]=ch[oldroot][1];
	f[ch[oldroot][1]]=root;
	clear(oldroot);
	updata(root);
	return;
}
int main() {
	int n,i,ans=0;
	scanf("%d",&n);
	for (i=1;i<=n;i++) {
		int opt,x;
		scanf("%d%d",&opt,&x);
		if (root==0)
		  insert(x),fff=opt;
		else
		if (fff==opt)
		  insert(x);
		else
		    {
		    	if (!find(x)) 
		    	{
		    		insert(x);
		    		int ans1=key[pre()],ans2=key[next()];
					del(x);
					if (ans1==0)
					  {
					    ans=(abs(ans2-x)%Mod+ans)%Mod;
						del(ans2);continue;
					  }
					if (ans2==0)
					  {
					    ans=(abs(ans1-x)%Mod+ans)%Mod;
						del(ans1);continue;
					  }
					if (abs(ans1-x)<=abs(ans2-x)) {
						ans=(abs(ans1-x)%Mod+ans)%Mod;
						del(ans1);
					} else {
						ans=(abs(ans2-x)%Mod+ans)%Mod;
						del(ans2);
					}
				}
				else
				  del(x);
			}
	}
	printf("%d",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值