HNOI2002--Splay

本文介绍了一种基于Splay树的数据结构实现,重点讲解了如何通过旋转操作维持树的平衡,并实现高效的插入、查找及维护操作。文章详细展示了Splay树的插入算法流程,包括节点的创建、旋转调整以及如何寻找前驱和后继节点来计算最小差值。

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

将每一个依次插入,与前驱和后继进行比较,选取差值小的。如果遇到相同的数已经在树中,则不插入。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100010
#define inf 0x3f3f3f3f
int pre[maxn],key[maxn],ch[maxn][2],root,tot1;
int n;
void NewNode(int & r,int father,int k)
{
	r = ++tot1;
	pre[r] = father;
	key[r] = k;
	ch[r][0] = ch[r][1] = 0;
}

//旋转,kind为1为右旋,kind为0为左旋
void Rotate(int x,int kind)
{
	int y = pre[x];
	//类似SBT,要把其中一个分支先给父节点
	ch[y][!kind] = ch[x][kind];
	pre[ch[x][kind]] = y;
	//如果父节点不是根节点,则要和父节点的父节点连接起来
	if(pre[y])
		ch[pre[y]][ch[pre[y]][1]==y] = x;
	pre[x] = pre[y];
	ch[x][kind] = y;
	pre[y] = x;
}

//Splay调整,将根为r的子树调整为goal
void Splay(int r,int goal)
{
	while(pre[r] != goal)
	{
		//父节点即是目标位置,goal为0表示,父节点就是根节点
		if(pre[pre[r]] == goal)
			Rotate(r,ch[pre[r]][0] == r);
		else
		{
			int y = pre[r];
			int kind = ch[pre[y]][0] == y;
			//两个方向不同,则先左旋再右旋
			if(ch[y][kind] == r)
			{
				Rotate(r,!kind);
				Rotate(r,kind);
			}
			//两个方向相同,相同方向连续两次
			else
			{
				Rotate(y,kind);
				Rotate(r,kind);
			}
		}
	}
	//更新根节点
	if(goal == 0)	root = r;
}

int Insert(int k)
{
	int r = root;
	while(ch[r][key[r]<k])
	{
		//不重复插入
		if(key[r] == k)
		{
			Splay(r,0);
			return 0;
		}
		r = ch[r][key[r]<k];
	}
	NewNode(ch[r][k>key[r]],r,k);
	//将新插入的结点更新至根节点
	Splay(ch[r][k>key[r]],0);
	return 1;
}

//找前驱,即左子树的最右结点
int get_pre(int x)
{
	int tmp = ch[x][0];
	if(tmp == 0)	return inf;
	while(ch[tmp][1])
		tmp = ch[tmp][1];
	return key[tmp] - key[x];
}

int get_next(int x)
{
	int tmp = ch[x][1];
	if(tmp == 0)	return inf;
	while(ch[tmp][0])
		tmp = ch[tmp][0];
	return key[tmp] - key[x];
}

int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		root = tot1 = 0;
		int ans = 0;
		for(int i = 1;i <= n;i++)
		{
			int num;
			if(scanf("%d",&num)==EOF) num = 0;
			if(i == 1)
			{
				ans += num;
				NewNode(root,0,num);
				continue;
			}
			if(Insert(num)==0)	continue;
			int a = get_next(root);
			int b = get_next(root);
			ans += min(a,b);
		}
		printf("%d\n",ans);
	}
	return 0;
}



 风格更新后:

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <algorithm>  
using namespace std;  
#define inf 0x3f3f3f3f  
#define maxn 100010  
#define LL long long int  
#define Key_value ch[ch[root][1]][0]  
  
inline int min(int a,int b)  
{  
    return a>b?b:a;  
}  
  
struct SplayTree  
{  
    int pre[maxn],key[maxn],ch[maxn][2],root,cnt;  
      
    void init()  
    {  
        root = cnt = 0;  
    }  
      
    void NewNode(int & r,int father,int k)  
    {  
        r = ++cnt;  
        pre[r] = father;  
        ch[r][0] = ch[r][1] = 0;  
        key[r] = k;  
    }  
      
    int Insert(int k)  
    {  
        int r = root;  
        while(ch[r][key[r]<k])  
        {  
            if(key[r] == k)  
            {  
                Splay(r,0);  
                return 0;  
            }  
            r = ch[r][key[r]<k];  
        }  
        NewNode(ch[r][k>key[r]],r,k);  
        Splay(ch[r][k>key[r]],0);  
        return 1;  
    }  
      
    int Get_Pre(int r)  
    {  
        int tmp = ch[r][0];  
        if(tmp == 0)    return inf;  
        while(ch[tmp][1])  
            tmp = ch[tmp][1];  
        return key[r] - key[tmp];  
    }  
      
    int Get_Next(int r)  
    {  
        int tmp = ch[r][1];  
        if(tmp == 0)    return inf;  
        while(ch[tmp][0])  
            tmp = ch[tmp][0];  
        return key[tmp] - key[r];  
    }  
  
    void Rotate(int x,int kind)  
    {  
        int y = pre[x];  
        ch[y][!kind] = ch[x][kind];  
        pre[ch[x][kind]] = y;  
        if(pre[y])  
            ch[pre[y]][ch[pre[y]][1]==y] = x;  
        pre[x] = pre[y];  
        ch[x][kind] = y;  
        pre[y] = x;  
    }  
      
    void Splay(int r,int goal)  
    {  
        while(pre[r] != goal)  
        {  
            int y = pre[r],z = pre[y];  
            if(pre[pre[r]] == goal)  
            {  
                Rotate(r,ch[pre[r]][0]==r);  
            }  
            else  
            {  
                int y = pre[r];  
                int kind = ch[pre[y]][0] == y;  
                if(ch[y][kind] == r)  
                {  
                    Rotate(r,!kind);  
                }  
                else  
                {  
                    Rotate(y,kind);  
                    Rotate(r,kind);  
                }  
            }  
        }  
        if(goal == 0)   root = r;  
    }  
      
    void solve(int n)  
    {  
        init();  
        int num,ans = 0;  
        for(int i = 1;i <= n;i++)  
        {  
            scanf("%d",&num);  
            if(i == 1)  
            {  
                NewNode(root,0,num);  
                ans += num;  
            }  
            else  
            {  
                if(Insert(num)==0)  continue;  
                int a = Get_Next(root);  
                int b = Get_Pre(root);  
                ans += min(a,b);  
            }  
        }  
        printf("%d\n",ans);  
    }  
}spt;  
  
int main()  
{  
    int n;  
    while(scanf("%d",&n)!=EOF)  
    {  
        spt.solve(n);  
    }  
    return 0;  
}  




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值