浅谈splay

article/2025/11/9 15:55:41

例题:

给出一个长度为n序列a。
有m次操作,每次操作可以修改a[i],在第i个数前插入一个数x,或查询区间[l,r]的最大值。

1≤n≤100000,1≤m≤100000。

强制在线

看到这道题最自然的反应就是用线段树,但有了插入操作线段树就不好处理了,需要离线才能做。而题目又要求强制在线,我们就只能使用splay了


什么是splay?

  • splay是一棵二叉搜索树,满足一个节点右子树的所有节点小于它,而左子树的所有节点大于它。
  • splay通过旋转它的节点来实现插入,查询区间极值、第K大值等操作。

旋转

旋转在splay当中是最基本的操作,splay就是通过对树的旋转来实现其他操作的。
如图,将节点Y旋转到X。如果直接旋转,那么X就有了三个子节点,不再是一棵二叉树。因为splay是一棵二叉搜索树,所以在子树3中的节点都是大于节点Y的。我们可以把子树3的父节点指向Y,从而保证这是一棵二叉树。
右旋为zig,左旋为zag,图中给出的是左旋。
这里写图片描述

  • zig-zig

    如图,将X旋到Y,先左旋Z,在左旋X,也就是zig-zig,与之对应的操作是zag-zag。
    这里写图片描述

  • zig-zag

    当要旋转时为下图的情况,应先zig(x),再zag(x)。同样,如果反过来,便是zag-zig。
    这里写图片描述

其实可以完全不用管旋转的顺序,但按照上文的方式去旋转会快很多,均摊 log(n) 。这个tarjan会证。
如果不是很理解,可以画一下图,手玩一下。

在知道如何修改后,就可以用splay实现其他操作了。
接下来会介绍几个常用操作。


修改

单点修改就不说了,直接改变节点的值就可以了,这里我们讲区间修改。
如果要将一个序列上x~y全部加上一个数Z,怎么办?
将x-1旋到根,再将y+1旋到x-1的子节点。这时,y+1的右子树便是x~y的全部节点,我们再这棵子树的根上打一个tag即可。
这里写图片描述
再每一次旋转的时候,记得要把tag下传,旋转完了还要updata。


插入

要在x和y之间插入一个数 (x<y) ,按照上面的思路,将x旋到根,再将y旋到x的子节点。
我们发现,y的右节点是空的,这时直接插入一个数就好了。
这里写图片描述


第k大值

要处理第k大值,对于一个节点x,我们多维护一个值size[x],表示以节点x为根的这个子树大小。
这里写图片描述
对上图来说,我们要查询第10大值。
size[2]+节点1+size[12]=8+1+1=9
所以节点6就是就是第10大值。


翻转

将区间L~R中的元素翻转,如图:
这里写图片描述
貌似不好实现……
根据区间修改的套路,我们将L-1旋的根,R+1旋到L-1的子节点,那么R+1的左子树就是区间L~R。
将splay中的一个节点的儿子节点对调,其实就是将这个节点在序列中左边和右边对调(自己脑补一下)
所以将这棵子树中的每一个节点对调即可实现翻转。


其实splay理解起来并不难,主要知道如何旋转就可以了,但实现起来会略微有点复杂。
这里给出splay的模板。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long 
#define isR(x) (b[f[x]][1]==x)
using namespace std;
const LL N=200001;
LL n,m,a[N],f[N],b[N][2],s[N],rmd[N],c[N],root,tag[N];
LL build(LL l,LL r)
{if (l>r) return 0;LL mid=(l+r)/2;rmd[mid]=1;s[mid]=r-l+1;if (l!=r){b[mid][0]=build(l,mid-1);b[mid][1]=build(mid+1,r);f[b[mid][0]]=f[b[mid][1]]=mid;c[mid]=max(max(c[b[mid][0]],c[b[mid][1]]),a[mid]);}else c[mid]=a[mid];return mid;
}
void update(LL x)
{s[x]=s[b[x][0]]+s[b[x][1]];c[x]=max(max(c[b[x][0]]+tag[b[x][0]],c[b[x][1]]+tag[b[x][1]]),a[x]*rmd[x]);
}
void put(LL x)
{if (tag[x]==3 && x==4)printf("");tag[b[x][0]]+=tag[x];tag[b[x][1]]+=tag[x];a[x]+=tag[x];tag[x]=0;
}
void rotate(LL x) {LL y=f[x],z=isR(x);put(y);put(x);b[y][z]=b[x][z^1];if (b[x][z^1]!=0) f[b[x][z^1]]=y;f[x]=f[y];if (f[y]!=-1) b[f[y]][isR(y)]=x;b[x][z^1]=y;f[y]=x;update(y);
}
void splay(LL x,LL y) {if (y==-1) root=x;while (f[x]!=y){if (f[f[x]]!=y){if (isR(x)!=isR(f[x])) rotate(x); else rotate(f[x]);}rotate(x);}update(x);
}
int main()
{//freopen("1.in","r",stdin);//freopen("1.out","w",stdout);memset(c,-0x7f,sizeof(c));LL i,j,k;scanf("%lld",&n);for (i=1;i<=n;i++) scanf("%lld",&a[i+1]);root=build(1,n+2);rmd[1]=0;rmd[n+2]=0;f[root]=-1;scanf("%lld",&m);for (i=1;i<=m;i++){LL x;scanf("%lld",&x);if (x==1) {LL l,r,y;scanf("%lld%lld%lld",&l,&r,&y);l++;r++;splay(r+1,-1);splay(l-1,r+1);LL z=b[l-1][1];tag[z]+=y;}else{LL l,r;scanf("%lld%lld",&l,&r);l++;r++;splay(r+1,-1);splay(l-1,r+1);printf("%lld\n",c[b[l-1][1]]+tag[b[l-1][1]]);}}
}

如果有不懂的地方,或文章有错误,可在评论留言。


http://chatgpt.dhexx.cn/article/O0wkCv2w.shtml

相关文章

关于splay的一些说明

前言splay出现的背景它的操作 push_uprotatesplayfindinsertnextdeletefindkthmain 前言 暑假快过完了,大家感觉是不是很棒!gay房也体验过最新的断电模拟器了. 好吧,在开讲之前我还是得说一个.刀剑神域的外传实在太好看了! 除了精彩的战斗场面,神一般的人设和强大的剧情,比…

Splay入门详解

Splay入门详解 写在前面 听说平衡树是一种强大的数据结构&#xff0c;听同年级或高年级大佬们讲起来也感觉很牛笔的亚子&#xff0c;而最近XC又叫我们去学习一下 L C T LCT LCT&#xff01;&#xff1f; 又因为 S p l a y Splay Splay是学习 L C T LCT LCT的基础&#xff0c;…

【学习笔记】Splay

普通平衡树 模板题链接 1、引入 一种二叉树&#xff0c;这棵树满足任意一个节点&#xff0c;它的左儿子的权值<自己的权值<右儿子的权值 这种树叫做二叉查找树&#xff0c;这个概念应该在初赛中见过了吧 Splay就是利用这个结构来实现的 2、变量 模板题的7大变量 s…

平衡树详解(Splay)

引入 先看例题&#xff1a;&#xff08;洛谷 P3369 【模板】普通平衡树&#xff09; 您需要写一种数据结构&#xff0c;来维护一些数&#xff0c;其中需要提供以下操作&#xff1a; 1.插入 x x x 数 2.删除 x x x 数(若有多个相同的数&#xff0c;因只删除一个) 3.查询 x x…

Splay入门解析【保证让你看不懂(滑稽)】

upd&#xff1a;忽然发现直接在百度上搜索 splay s p l a y 就会搜索到我这篇文章&#xff1f;小蒟蒻瑟瑟发抖。 因为CSDN这边我基本不会看回复什么的&#xff0c;所以如果有问题还是请移步cnblogs里面吧 Cnblogs里面这篇文章的链接 BST真是神奇的东西。。。 而且种类好多呀…

Splay Tree

类别&#xff1a;二叉排序树 空间效率&#xff1a;O(n) 时间效率&#xff1a;O(log n)内完成插入、查找、删除操作 创造者&#xff1a;Daniel Sleator和Robert Tarjan 优点&#xff1a;每次查询会调整树的结构&#xff0c;使被查询频率高的条目更靠近树根。 注&#xff1a;所有…

【算法详解】splay的初步了解

qwq表示最近感受到了不停课的鸭梨啊&#xff0c;好难搞啊……算法太难学了……我好菜啊qwq 其实半个多月前就可以写这篇文章&#xff0c;不过由于时间紧张没写emmmmmm&#xff0c;不扯闲言乱语了&#xff0c;如果有什么写的不好的地方凑活一下吧2333333333 splay是一种可以使树…

splay详解

一&#xff1a;什么是splay&#xff08;伸展树&#xff09; 首先了解二叉排序树 二叉排序树或者是一棵空树&#xff0c;或者是具有下列性质的 二叉树&#xff1a; &#xff08;1&#xff09;若左子树不空&#xff0c;则左子树上所有结点的值均小于或等于它的 根结点的值&#…

Splay 总结基础精华

前言&#xff1a; 第一次学习Splay是2月份&#xff0c;打板子的时候是3月份&#xff0c;Ac是4月份&#xff0c;写这篇博客是6月初&#xff1b;原因是因为我竟然发现我忘了Splay的板子了&#xff01;很慌&#xff0c;必须总结一下&#xff01; 不敢说是最详细的&#xff0c;但希…

关系型数据库与非关系型数据库详解

关系数据库与非关系型数据库 一、数据库概述1、关系型数据库2、非关系型数据库 二、数据库区别1、数据存储方式不同2、扩展方式不同3、对事务性的支持不同 三、非关系型数据库产生背景四、Redis简介1、Redis 优点 五、Redis 安装部署六、Redis 命令工具&#xff08;1&#xff0…

关系型数据库RDS基本简介

OSS存放非结构化的数据&#xff0c;如&#xff1a;音频、视频、图片 rds存放结构化的数据&#xff0c;如&#xff1a;一张表&#xff0c; RDS产品概要 可以根据业务的需求进行弹性伸缩。 采用主从备份架构&#xff0c;三节点数据存储&#xff0c;具备高可用性和数据可靠性 …

2 关系型数据库是什么?

目录结构 关系型数据库基本概念结构化查询语言数据定义语言&#xff08;DDL&#xff09;数据查询语言&#xff08;Data Query Language, DQL&#xff09;数据操纵语言&#xff08;Data Manipulation Language, DML&#xff09;数据控制语言&#xff08;Data Control Language, …

常见的关系型数据库有哪些

Oracle Database&#xff1a;由Oracle公司开发和维护的商业关系型数据库&#xff0c;具有广泛的应用场景和功能。 MySQL&#xff1a;开源关系型数据库&#xff0c;常用于Web应用程序和小型企业应用。 Microsoft SQL Server&#xff1a;由Microsoft公司开发和维护的商业关系型…

Bezier曲线快速相交计算(含代码)

Bezier曲线快速相交计算 背景介绍算法思路解释和分析示例参考资料 背景介绍 很多时候&#xff0c;需要计算曲线段与曲线段是否有交点。常规的思路是直接联立方程求解。不过&#xff0c;直接求方程的解这种思路通常在计算上开销较大。 针对任意曲线&#xff0c;曲线的方程阶次…

js绘制贝塞尔曲线(Bézier-Curve)

贝塞尔曲线(Bzier curve)&#xff0c;又称贝兹曲线或贝济埃曲线&#xff0c;是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线&#xff0c;贝兹曲线由线段与节点组成&#xff0c;节点是可拖动的支点&#xff0c;线段像可伸缩的皮筋&#xff0c;我们…

Bezier曲线与B-Spline曲线

微分几何基础 微分集合是用微分的方法来研究曲线的局部性质&#xff0c;如曲线的弯曲程度等。 一条可以用参数表示的三维曲线是一个有界点集&#xff0c;可以写成一个带参数的、连续的、单值的数学函数&#xff1a; { x x ( t ) y y ( t ) z z ( t ) 0 ⩽ t ⩽ 1 p p ( t…

初识贝塞尔(bezier)曲线

文章目录 资料援引贝塞尔曲线的用途一阶贝塞尔&#xff08;bezier&#xff09;曲线二阶贝塞尔&#xff08;bezier&#xff09;曲线三阶贝塞尔&#xff08;bezier&#xff09;曲线高阶贝塞尔&#xff08;bezier&#xff09;曲线三阶贝塞尔曲线求插值&#xff08;Slerp&#xff0…

贝塞尔曲线(Bezier Curve)原理、公式推导及matlab代码实现

1. 定义 贝塞尔曲线(Bezier curve)&#xff0c;又称贝兹曲线或贝济埃曲线&#xff0c;是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线&#xff0c;贝兹曲线由线段与节点组成&#xff0c;节点是可拖动的支点&#xff0c;线段像可伸缩的皮筋&#…

Bezier(贝塞尔曲线通用规律算法-DEMO)

之前也看过一些相关贝塞尔曲线的知识&#xff0c;但就是一直没有实践应用&#xff1b; 今天&#xff0c;听到有同事&#xff1a;程序、美术&#xff0c;在讨论相关的&#xff0c;人物的曲线路径行走的问题&#xff1b; 一些数学比较牛X的&#xff0c;说了用2阶&#xff0c;或…

bezier曲线原理(简单阐述)

原理和简单推导&#xff08;以三阶为例&#xff09;&#xff1a; 设P0、P02、P2是一条抛物线上顺序三个不同的点。过P0和P2点的两切线交于P1点&#xff0c;在P02点的切线交P0P1和P2P1于P01和P11&#xff0c;则如下比例成立&#xff1a; 这是所谓抛物线的三切线定理。 当P0&…