poj3481 用伸展树来做

本文详细介绍了伸展树中删除最小值和最大值的操作方法,包括删除最小值时的根节点替换和删除最大值时的左子树继承,以及删除节点后的Splay操作以维护树的平衡。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string.h>
#include <queue>       //poj3481 伸展树(包括删除的操作)
#define N 100010
using namespace std;
int pre[N], key[N], ch[N][2], num[N], root, tot;
/*
4、删除最大最小:
a)删除最小:
    首先执行查找最小的操作。
这时,要删除的节点就在根上。根据二叉查找树的特点,根没有左子节点。
使用根的右子结点作为新的根,删除旧的包含最小值的根。
b)删除最大:
首先执行查找最大的操作。
删除根,并把被删除的根的左子结点作为新的根。
5、删除:
        将要删除的节点移至根。
        删除根,剩下两个子树L(左子树)和R(右子树)。
        使用DeleteMax查找L的最大节点,此时,L的根没有右子树。
        使R成为L的根的右子树。
*/
void newnode(int &r, int father, int k, int n)
{
	r=++tot;
	pre[r]=father;
	ch[father][key[father]<k]=r;
	key[r]=k;
	num[r]=n;
	ch[r][0]=ch[r][1]=0;
	return ;
}
void rotate(int x, int kind)   //kind为0表示左旋,kind为1表示右旋
{
	int k=pre[x], g;
	ch[k][!kind]=ch[x][kind];
	pre[ch[x][kind]]=k;
	ch[x][kind]=k;
	pre[x]=pre[k];
	g=pre[k];
	pre[k]=x;
	if(pre[k]==0)
		return ;
	ch[g][key[g]<key[x]]=x;
	return ;
}
void Splay(int x, int goal)
{
	int k, g, h;
	while(pre[x]!=goal)
	{
		k=pre[x];
		if(pre[k]==goal)
		{
			rotate(x, key[k]>key[x]);
		}
		else 
		{
			g=(ch[k][0]==x?0:1);
			h=(ch[pre[k]][0]==k?0:1);
			if(g==h)
			{
				rotate(k, !g);
				rotate(x, !g);
			}
			else 
			{
				rotate(x, key[k]>key[x]);
				rotate(x, key[pre[x]]>key[x]);
			}
		}
	}
	if(!goal)root=x;
	return ;
}
void insert(int k, int n)
{
	int r=root, g, h;
	if(!r)
	{
		newnode(root, 0, k, n);
		return ;
	}
	while(r)
	{
		g=r;
		if(key[r]>k)
			r=ch[r][0];
		else r=ch[r][1];
	}
	newnode(h, g, k, n);
	Splay(h, 0);
	return ;
}
void dele(int x, int kind) //kind为0表示只有左子树,kind为1表示只有右子树
{
	Splay(x, 0);
	if(kind)
	{
		root=ch[x][1];
		pre[root]=0;
	}
	else
	{
		root=ch[x][0];
		pre[root]=0;
	}
	return ;
}

int getleft()
{
	int r=root, k, g;
	if(!root)
		return 0;
	while(r)
	{
		k=r;
		r=ch[r][0];
	}
	g=num[k];
	dele(k, 1);
	return g;
}
int getright()
{
	int r=root, k, g;
	if(!root)
		return 0;
	while(r)
	{
		k=r;
		r=ch[r][1];
	}
	g=num[k];
	dele(k, 0);
	return g;
}
int main()
{
	int n, a, b;
	root=tot=0;
	while(scanf("%d", &n)&&n)
	{
		if(n==1)
		{
			scanf("%d%d", &a, &b);
			insert(b, a);
			continue;
		}
		if(n==2)
		{
			printf("%d\n", getright());
		}
		if(n==3)
		{
			printf("%d\n", getleft());
		}
	}
	return 0;
}


		

	



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值