伸展树的构建和最基本的插入与查询

Splay树(伸展树) 伸展树(Splay Tree),是一种二叉平衡搜索树,时间复杂度均摊为O(logN),即splay树做m次操作的复杂度为O(mlogN)。 在伸展树上的一般操作都基于伸展操作/提根操作: 假设想要对一个二叉搜索树执行一系列的查找操作,为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法, 在每次查找之后对树进行重构,把被查找的条目搬移到离树根近 阅读详情

题目链接:http://acm.tzc.edu.cn/acmhome/problemdetail.do?method=showdetail&id=2924

描述
Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。Tiger拿出了公司的账本,
账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现

一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。

经济管理学上定义了一种最小波动值来衡量这种情况:
该天的最小波动值 = min{ |该天以前某天的营业额 - 该天的营业额 | }
当最小波动值越大时,就说明营业情况越不稳定。而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。
你的任务就是编写一个程序帮助Tiger来计算这一个值。第一天的最小波动值为第一天的营业额。

输入
测试数据多组,每组的第一行为正整数n(1 <= n <= 32767), 表示该公司从成立一直到现在的天数. 接下来的n行每行有一个整数Ai(Ai <= 1000000) , 
表示第i天的营业额。处理到EOF为止。

输出
每组数据占一行,每行输出一个整数,每天最小波动值的和。结果小于2^31

样例输入
6
5
1
2
5
4
6

样例输出
12

提示
5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12

思路:每次输入都找出之前与当前输入最接近的那个数,求出差的绝对值加到答案里。此题若用最暴力的方法,每次输入都从头循环一次,必然能求出答案,

但是数据量有点大,会超时。所以这里用伸展树求解,时间复杂度会大大降低。

关于伸展树若不了解的话,我推荐kernel@hcy的博客:http://www.cnblogs.com/kernel_hcy/archive/2010/03/17/1688360.html

这篇博客详细的说了伸展树的所有基本操作,在此我不再赘述,我只说一个我们做这题会利用到的特点。

伸展树:伸展树有一个最基本的特点,就是其左子树的所有节点的值一定比父节点小,其右子树的的所有节点的值一定比父节点大。

那么,我们如果每次读入,都把其放到根节点,那么我们只要找到左子树中最大的值,和右子树中最小的值,比较他们和当前输入的差的绝对值,更小的那个就是

当天的波动值了。

下面是AC代码(记得用G++提交,另外建议看完我推荐的那篇博客再来看代码,熟悉了那里的基本操作(通过左旋,右旋,更新根节点),才能看懂下面代码)

<pre name="code" class="cpp">#include<iostream>
#include <cstring>
#include <cstdio>
#define maxn 111111
using namespace std;
int n;
int root,tot;//root就是根节点的标号,tot记录节点总数量
int ans;
int pre[maxn],key[maxn],ch[maxn][2];//pre数组记录父节点的标号,key数组记录节点的值,ch记录其左右子节点的标号。标号从1开始,到总天数n
void NewNode(int &r,int father,int k)//建立一个新的节点
{
	r=++tot;//根的标号是r,要传指针,每次都要更新标号
		pre[r]=father;//father为父节点的标号,0则表示空,没有父节点
	key[r]=k;//记录r标号的值
	ch[r][0]=ch[r][1]=0;//其左右子节点为空,0表示左子节点,1表示右子节点
} 
void Rotate(int x,int kind)
{
	int y=pre[x];
	ch[y][!kind]=ch[x][kind];//根据旋转特性,x的右子树变成y的左子树,或其左子树变成y的右子树,相当于y认了个儿子=,=
	pre[ch[x][kind]]=y;//将要改变的x的子树的父节点换成y,相当于儿子承认了上面那个父亲=,=
	if(pre[y])
		ch[pre[y]][ch[pre[y]][1]==y]=x;//如果父节点不是根结点,则要和父节点的父节点连接起来
	pre[x]=pre[y];//y和x的位置要换,所以y的父节点便成x的父节点
	ch[x][kind]=y;//x变成y的父节点,认y做儿子
	pre[y]=x;//y的父节点变成x,y也承认了x这个父亲=,=
}
void Splay(int r,int goal)//看Splay代码前看看我推荐的博客,看懂了对下面的操作会更容易理解
{
	while(pre[r]!=goal)//本身不是根节点,则要将其旋转成根节点
	{
		if(pre[pre[r]]==0)//若其父节点就是根节点,则直接对r旋转一次
			Rotate(r,ch[pre[r]][0]==r);
		else{
			int y=pre[r];//记录父节点的标号
			int kind=ch[pre[y]][0]==y;//kind用于判断是进行两次同样的旋转还是不同的旋转
			if(ch[y][kind]==r)//三个节点不在同一条线上,先左旋后右旋或者先右旋后左旋
			{
				Rotate(r,!kind);
				Rotate(r,kind);
			}else{
				Rotate(y,kind);//在同一条线上,连续两次左旋或连续两次右旋
				Rotate(r,kind);
			}
		}
	}
	root=r;//根节点更新成为当前的节点标号,当前的节点已经旋转成根节点
}
int Insert(int k)
{
	int r=root;//记录当前标号
	while(ch[r][key[r]<k])//若r的子节点存在,则一直向下查找是否有值为k的,有则返回0
	{
		if(key[r]==k)
		{
			Splay(r,0);
			return 0;
		}
		r=ch[r][key[r]<k];//key[r]<k若成立,则返回1,表示的是r的右子节点,否则为左子节点
	}
	NewNode(ch[r][k>key[r]],r,k);//没有找到相等的值,则建一个节点,将其插入伸展树
	Splay(ch[r][k>key[r]],0);//开始判断情况,将新插入的点旋转到根节点
	return 1;
}

int get_next(int x)//找右子树最小的值
{
	int temp=ch[x][1];//记录右子树
	if(!temp)return 999999999;//若右子树不存在,返回无穷大
	while(ch[temp][0])//当右子树的左子树存在,则更新temp的值
		temp=ch[temp][0];
	return key[temp]-key[x];//返回波动值
}
int get_pre(int x)//同上
{
	int temp=ch[x][0];
	if(!temp)return 999999999;
	while(ch[temp][1])
		temp=ch[temp][1];
	return key[x]-key[temp];
} 
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		ans=root=tot=0;
		int num;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&num);
			if(i==1)
			{
				ans+=num;//第一天直接加
				NewNode(root,0,num);//建立第一个节点
				continue;
			}
			if(!Insert(num))continue;//判断是否输入过相同的值,若有,则当天波动值一定是0,不用再查找
			int a=get_next(root);//若没有输入过相等的值,则查找其左子树中的最大值和右子树中的最小值,求出它们和当天值的差的绝对值,更小的那个为当天波动值
			int b=get_pre(root);
			ans+=min(a,b);
		}
		printf("%d\n",ans);
	}
	return 0;
}


 





Burp靶场实战:JWT签名绕过漏洞分析与利用 本文通过Burp Suite靶场实战,深入剖析了JWT签名绕过漏洞的多种攻击手法,包括签名未验证、alg:none攻击、弱密钥爆破、JWK/JKU头注入、KID路径遍历及算法混淆攻击。文章详细演示了利用过程,并提供了关键的防御指南,帮助开发和安全人员加固JWT实现,确保认证安全。 阅读详情

相关推荐

Android/AutoMotive 多用户文件操作与权限管理

本文深入探讨了Android/Automotive多用户系统的文件操作与权限管理机制。文章阐述了多用户隔离与共享的核心原理,重点介绍了如何使用adb指令精准管理不同用户的应用与数据,并提供了在Android Automotive车载场景下实现安全跨用户数据共享与权限控制的最佳实践。

weixin_29214691的博客 160

伸展树(Splay)

伸展树(Splay) 伸展树的作用范围很广,在某些情况下甚至可以代替线段树,伸展树最突出的特点就是区间操作:区间翻转,区间插入,区间删除,与其他二叉搜索树相比它能使得总体时间效率得到平摊,使得总效率为O(mlog n),当操作涉及到以区间为单位的位置变动时,就会使用到伸展树

C_eeking的博客 1386

高速SerDes均衡技术解析

均衡技术是高速SerDes链路中补偿信道损耗和失真的核心技术,通过FFE、CTLE和DFE三种主要方法对抗码间干扰(ISI)。FFE在发射端预补偿前光标干扰,CTLE通过提升高频增益补偿信道损耗,DFE则精准消除后光标干扰。三种技术各具优势:FFE实现简单且不放大噪声,CTLE功耗低易于集成,DFE能自适应调整且保持信噪比。这些技术协同工作可有效提升系统传输速率和可靠性。

一只豌豆象的博客 1945

伸展树的查找、插入、删除

在信息处理中,刚被访问的数据,很有可能在短时间内被再次访问。在计算机系统中,同样如此。在总结点数为n的AVL树中,访问m次相邻数据共需要mlogn的时间。如果我们把经常访问的数据都放在树的顶端,那么时间就会减少很多。在此,我们引入了伸展树这一概念。 伸展树的概念 最基本的概念,逐层伸展:节点一旦被访问,就将其转移至树根。这一操作可以经过若干次单旋Zig或Zag操作来完成。自下而上,逐层单旋,直至v...

JTY541464341的博客 1681

大模型训练流程(四):PPO强化学习实战与调优指南

本文详细解析了大模型训练中PPO强化学习的实战应用与调优技巧,涵盖RLHF核心原理、PPO算法实现及显存优化策略。通过具体案例和代码示例,指导开发者有效提升模型回答质量与安全性,避免常见训练陷阱。

weixin_29051811的博客 437

模电专题-MOS管的放大电路分析

在实际应用中,我们经常会使用到功率MOS,这时通常不会将它当成一个开关使用,而是当成一个放大器来使用,那这就需要让其工作在放大状态。参考下图中的mos管的特性曲线,右图中的输出特性曲线中有一根红色的分界线,这个线就是区分mos管工作状态的分界线,在红线的左边,mos管工作在可变电阻区,也就是线性区;在红线的右边mos管工作在恒流区,也就是饱和区。当然,还有一个截止区。本文分析主要运用模电课本中的理论计算验证。

Anitawen的博客 2万+

伸展树

伸展树,是一种二叉排序树。它可以baozheng

flyapy 840

经典蓝牙中的Sniff、Hold与Park模式

若主设备在Sniff Attempt窗口外发送数据,从设备无法接收,需依赖重传机制。移动时立即传输数据。:Sniff Interval=20ms,Attempt=1时隙。:传感器每2秒唤醒一次同步信标,主设备按需唤醒特定传感器采集数据。Slave进入Sniff模式:每20ms唤醒1个时隙监听数据。:设备需要短暂执行高优先级任务(如扫描其他蓝牙设备)。:无数据传输超时后,设备可能自动进入Sniff模式。:主设备通过信标唤醒从设备,或从设备主动请求退出(:平衡功耗与响应速度,适合间歇性数据传输设备。

shishuangquan111的博客 1673

Splay伸展树学习笔记

Splay伸展树 有篇Splay入门必看文章 —— 优快云链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入、查找、删除 创造者:Daniel Sleator 和 Robert Tarjan 优点:每次查询会调整树的结构,使被查询频率高的条目更靠近树根。 Tree Rotation 树的旋转...

weixin_30828379的博客 246

C#.NET斗地主服务端核心架构与高性能实现

斗地主作为典型的实时对战棋牌逻辑,本质是状态驱动的分布式协同问题。其技术内核涵盖有限状态机建模、低延迟网络同步、无GC内存操作与轻量级AI决策等关键能力。在.NET平台下,借助Span<T>、ImmutableArray、命令/事件总线与内存池等特性,可构建出高吞吐(200+ QPS)、低延迟(<150ms)、强一致的可落地服务端。本文聚焦C#.NET生态中斗地主核心模块的设计取舍与压测验证,深入解析状态机驱动、CardSet结构体优化、Kestrel中间件锁、规则+概率混合AI等实战方案,为实时对战类业务

weixin_29726381的博客 345

【AAAI 2025】轻量级特征增强新范式!FCM 模块助力小目标检测,即插即用提升模型泛化能力

本文介绍了AAAI 2025提出的轻量级特征增强新范式FCM模块,它通过显式分离并双向交互语义与空间特征,有效解决了小目标检测中特征信息失配的核心难题。该模块设计精巧,计算开销极低,能够即插即用式地嵌入YOLO等主流检测网络,显著提升模型对小目标的泛化检测能力,尤其适用于遥感、自动驾驶等对计算资源敏感的实际场景。

weixin_29056145的博客 287

一个伸展树的实现

伸展树实现(java语言版本) 一、伸展树的基本概念 伸展树是一种二叉搜索树,伸展树也是一种平衡树,不过伸展树并不像AVL树那样对树的平衡有很严格的要求(左右孩子高度之差不能超过1),伸展树通过一系列的伸展操作,可以保证对伸展树的任意连续M次操作,其时间复杂度不会超过MlogN级别,并且伸展树的实现相较于AVL树也简单了很多,不论是插入还是删除算法 二、伸展树的伸展操作 伸展树之所以能够保证MlogN的界,就是因为伸展树的伸展操作,每一次调用伸展树的search方法查找一个结点的时候,如果存在,那么就

西城风雨楼 737

不会写GLSL?用Cesium 1.120 + Heatmap.js 2.0.5也能搞定动态洪水模拟(附完整源码)

本文介绍了一种无需GLSL编程的3D洪水动态模拟方案,结合Cesium 1.120和Heatmap.js 2.0.5实现高效可视化。通过数据层、可视化层和集成层的技术降级方案,开发者可以快速构建专业级洪水演进效果,适用于应急管理、水利工程等场景。文章包含完整源码和性能优化技巧。

weixin_30329623的博客 520

伸展树-搜索树

/ 因为根节点被删除了,搜索会将右子树中节点值最接近查找数值的节点返回,这个节点就是右子树中最小的节点,然后右子树中最小节点必伸展至根,且(因无类同节点)其左子树必空。// 根节点 = 其右子树,也就是原本的根节点已经被删除了。在这种情况中,X有一个父节点P和祖父节点G(P的父节点)。// 令 新的根节点左子树 = 上面存储的左子树。存在,此时有一个隐含信息,因为搜索到了该节点,那么这个节点此时已经被伸展到树根了。关于查询操作中,将节点伸展至根节点的操作,应用伸展(splaying)技术。

lq 1316

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

伸展树及从上而下的伸展树

我们知道AVL树为了保持严格的平衡,所以在数据插入上会呈现过多的旋转,影响了插入和删除的性能,此时AVL的一个变种 伸展树(Splay)就应运而生了,我们知道万事万物都遵循一个“八二原则“,也就是说80%的人只会用到20%的数据,比如说我们 的“QQ输入法”,平常打的字也就那么多,或许还没有20%呢。   一:伸展树  1:思想     伸展树的原理就是这样的一

Aiphis的博客 660

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

伸展树(splay tree)

什么是伸展树?首先,伸展树(splay tree)是一颗二叉搜索树,它的定义是建立在二叉搜索树之上,并且它是基于类似程序局部性原理的假设:一个节点在一次被访问后,这个节点很可能不久再次被访问。那么伸展树的做法就是在每次一个节点被访问后,我们就把它推到树根的位置。正像程序局部性原理的实际效率被广泛证明一样,伸展树在实际的搜索效率上也是非常高效的。尽管存在最坏情况下单次操作会花费O(N)的时间,但是这种

Wenqi's Blog 1145

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

算法笔记——伸展树

伸展树

m0_67142204的博客 1435

splay伸展树 指针型 平衡树基本操作 序列维护 详细讲解+总结

转载请保留本博客源地址:http://blog.youkuaiyun.com/u011327397/article/details/53783700 本来是要去学lct,然后看到要用splay我又不会,就开始看splay了,然后发现splay艹起来特别爽,但是序列操作网上没看到有详讲的,理解的时候很多奇怪的问题(无限RE)再加上指针调试复杂度高,花了很多时间,就觉得来写一个讲解吧。

anantheparty的博客 3744

POJ 3580 SuperMemo(伸展树的基本操作)

题目大意:给你六个操作,让你实现这些功能。 解题思路:伸展树的基本应用,用伸展数实现各种功能。 SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 10404   Accepted: 3320 Case Time Limit: 2000MS

I am a slow walker, but I never walk backwards! 1578

伸展树最重口味题 维修数列

链接 : http://www.lydsy.com/JudgeOnline/problem.php?id=1500 如果都做到这题了,就不多说了 有很多的注意点,代码中有注释 #include #include #include using namespace std; const int inf = ~0u>>2; #define L ch[x][0] #define R ch[x][1]

努力奋斗才能梦想成真 1972

伸展树模板题

伸展树的功能: 1. 插入x数 2. 删除x数(若有多个相同的数,因只删除一个) 3. 查询x数的排名(若有多个相同的数,因输出最小的排名) 4. 查询排名为x的数 5. 求x的前驱(前驱定义为小于x,且最大的数) 6. 求x的后继(后继定义为大于x,且最小的数)

kkkGIGi_qtt 720

伸展树的读书笔记

最近开始了自己高级数据结构之旅,在这次旅行中,我将持续把一些高级的数据结构从理论到编码都过一遍,同时通过博客形式分享出来,希望大家指出不足之处!        二叉排序树是一种动态排序的数据结构,支持插入、删除、查找等操作,且平均时间复杂度为O(log(N)),但是普通二叉排序树不能保证树退化为一颗分支的情况,此时最坏情况下的时间复杂度为O(N)。此时,平衡二叉树的产生了。平衡二叉树是一种动态调

晓风残月xj 1270

C++学习之旅【C++伸展树介绍以及红黑树的实现】

本文作为C++学习之旅的重要篇章,重点介绍伸展树的核心特性与红黑树的C++实现细节,助力学习者掌握两种经典自平衡二叉搜索树。伸展树作为自适应树结构,核心在于通过伸展操作将访问节点移至根节点,优化热点数据访问效率,无需额外平衡信息,内存开销低且实现简洁,适用于局部性原理场景。红黑树则通过节点颜色约束实现近似平衡,遵循五大核心规则,确保操作时间复杂度稳定在O(log n),是C++ STL容器的底层核心实现。文中详细阐述红黑树的节点结构设计、旋转操作及平衡调整逻辑,结合C++模板特性提供可复用实现思路,对比两种

承于所学,探技术之渊;以代码求政,寻成长之道。 1889

伸展树的优势与应用场景

伸展树的最大优势在于“自适应性”,非常适合热点数据频繁访问的场景。将节点移到根节点,是为了保持树的动态平衡,同时优化后续操作效率。

catandrabbit的博客 1690

caioj1130:伸展树(模版)

目录 题目描述 伸展树的基本概念 定义结构体 更新控制的节点数的函数 增加一个点的函数 rotate旋转的函数(重要)  找某个值的编号的函数 插入的函数 删除的函数 找排名的函数  找某个排名对应的值的函数 找前驱的函数 找后继的函数 智障的主函数 完整代码 优快云常年出问题,所以注释的图里面可能会移位,请诸位稍微自己调整一下,谢谢!!! 题目描述 【题意描...

TJ 588

五、平衡二叉树——伸展树Splay

treep 伸展树 由于数据存在局部性原理,刚刚访问过的数据有很大可能在短时间内被再次访问,其相邻结点被访问的可能性也会提高。为了提高局部性查询的效率,伸展树诞生了。 伸展树的原理 伸展树在每次查询完一个数据后就将该数据对应的结点旋转至树根,在旋转的同时保持树的搜索性不变(中序遍历不变)。于是下次在查询相同的数据或是相邻的数据时,时间就会大大缩短。 伸展树在总体上的均摊效率为O(logn),m次查询的复杂度为O(mlogn) 实现细节 由于无需保持整棵树的平衡,伸展树的结点只需要记录左右子树和父结点的信息即

Shanhj的博客 468
上一篇: HDU 1698 线段树成段更新模板
下一篇: HDU1823-二维线段树
P_rogrammer
博客等级 码龄12年 0粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值