Splay学习总结

高级数据结构题库 网络课课后题 1、在5x5的矩阵中,有2个非零元素,则稀疏因子为____。 答案: 0.08 2、下列关于十字链表的表述正确的有: A、十字链表的节点只需要记录非零元素的值,不需要记录它们在矩阵中的位置。 B、一个全由非零元素组成的矩阵,若使用十字链表表示,也将获得效率的提升。 C、十字链表的每个节点只有一个指向后继元素的指针。 D、应用十字链表做矩阵乘法时,时间复杂度是O(... 阅读详情

title: ‘Splay学习总结’
categories: 算法
date: 2015-12-28 17:00:00
tags: [Splay,算法]


基本思路

Splay,即伸展树,以其鬼魅的伸展操作而得名。核心操作是通过旋转来把某个节点转到根节点,并通过旋转操作改变树的结构来保证复杂度均摊O(log n)。

旋转操作有单旋和双旋两种,而单旋是可以被卡成O(n)的复杂度的。下面主要介绍双旋:
若目标节点为x,则Splay旋转的情况有三种:
1. 如果x的父节点是根,那么将x旋上去即可
2. 如果x的父节点非根,而爷节点是根,且x和x的父节点处于同一方向上(即能连成一条直线),那么先将x的父节点转上去,再将x转上去。

3. 如果x的父节点非根,而爷节点是根,且x和x的父节点不在同一方向上(即为之字形?),那么先将x旋两次旋至根节点。


实现步骤

本人模板风格大多来源于白书+自己修改
(然而机房很多童鞋的代码都是%H,找不到同好啊,so sad)

基本操作

  • Update(更新)
inline void Update(int k){
    tr[k].size=tr[tr[k].ch[0]].size+tr[tr[k].ch[1]].sz+tr[k].s;
}
  • Rotate(旋转)
void Rotate(int &k,int d){ //d=0为右旋,d=1为左旋
    int t=tr[k].ch[d^1];
    tr[k].ch[d^1]=tr[t].ch[d]; tr[t].ch[d]=k;
    Update(k); Update(t); k=t;
}

维护离散元素

用于维护一些离散的数据

  • Splay(伸展)
void Splay(int &k,int x){//用于在树中找到元素x并提到根节点
    if(x!=tr[k].key){
        int d1=(x<tr[k].key?0:1),t=tr[k].ch[d1];
        int d2=(x<tr[t].key?0:1);
        if(t && x!=tr[t].key){ //双旋操作
            Splay(tr[t].ch[d2],x);
            if(d1==d2) Rotate(k,d1^1); //
            else Rotate(tr[k].ch[d1],d1);
        }
        Rotate(k,d1^1);
    }
}
  • Insert(插入)
void Insert(int &k,int x){
    if(!k){
        k=++cnt; tr[k].key=x;
        tr[k].ch[0]=tr[k].ch[1]=0; tr[k].size=tr[k].s=1;
        Splay(root,x);
        return;
    }
    tr[k].sz++;
    if(tr[k].key==x){
        tr[k].s++; Splay(root,x);
        return;
    }
    if(tr[k].key>x) Insert(tr[k].ch[0],x);
    else Insert(tr[k].ch[1],x);
}
  • Delete(删除)
    删除操作需要充分利用到Splay的伸展操作。先找到要删除的元素的前驱和后继,之后把前驱转到根节点,把后继转到根结点的右子节点,根据二叉树的性质,要删除的节点一定在其后继的左子树上且这棵树上就这一个节点,直接删除即可。
void Delete(int x){
    Splay(root,x);
    if(tr[root].s>1){
        tr[root].s--; tr[root].sz--;
        return;
    }
    if(!(tr[root].ch[0]*tr[root].ch[1])){
        root=tr[root].ch[0]^tr[root].ch[1];
        return;
    }
    int pre=0,suf=0;
    find_pre(root,x,pre); find_suf(root,x,suf);
    Splay(root,pre); Splay(tr[root].ch[1],suf);
    int pos=tr[tr[root].ch[1]].ch[0];
    tr[pos].sz=tr[pos].s=tr[pos].ch[0]=tr[pos].ch[1]=tr[pos].key=0;
    tr[tr[root].ch[1]].ch[0]=0;
    Update(tr[root].ch[1]); Update(root);
}

维护序列

对于维护序列,我们需要在序列的开头和结尾引进两个虚点,来方便我们在序列开头和结尾进行插入和删除等操作。

  • Splay(伸展)
void Splay(int &k,int x){//用于找到树中第x大的元素并提到树根,一般适用于维护序列的问题,即找到序列中处在第x位的元素
//  Pushdown(k);
//  if(tr[k].ch[0]) Pushdown(tr[k].ch[0]);
//  if(tr[k].ch[1]) Pushdown(tr[k].ch[1]);
    int d1=(tr[tr[k].ch[0]].sz<x?1:0),t=tr[k].ch[d1];
    if(d1==1) x-=tr[tr[k].ch[0]].sz+1;
    if(x){
        int d2=(tr[tr[t].ch[0]].sz<x?1:0);
        if(d2==1) x-=tr[tr[t].ch[0]].sz+1;
        if(x){
            Splay(tr[t].ch[d2],x);
            if(d1==d2) Rotate(k,d1^1);
            else Rotate(tr[k].ch[d1],d1);
        }
        Rotate(k,d1^1);
    }
}
  • Insert(插入)
    当要在序列的pos位置插入元素(新的序列)时,可以将序列第x位的节点转至根,第x+1位的节点转至根的右子节点,然后直接插入到x+1位的节点的左子节点即可。
    (由于一开始引进了虚点,所以我们需要将x+1位的节点转至根,第x+2位的节点转至根的右子节点)
void Insert(int x,char val){
    Splay(root,x+1); Splay(tr[root].ch[1],x+1-tr[tr[root].ch[0]].sz);
    //本应为Splay(tr[root].r,x+2-(tr[tr[root].ch[0]].sz+1));
    int k=++cnt;
    tr[k].key=val; tr[k].ch[0]=tr[k].ch[1]=0;
    tr[tr[root].ch[1]].ch[0]=k;
    Update(k); Update(tr[root].ch[1]); Update(root);
}
  • Delete(删除)
    类似插入,当删除序列[l,r]段的元素时,将序列第l-1位的元素转至根,第r+1位的元素转至根的右子节点,然后删除其左子节点。为了节省空间,一般我们需要将这些被删除的元素记录到一个循环队列中,重复使用这些被删除的编号。
    (由于之前引进的虚点,我们需要操作的是第l位和第r+2位的节点,下同)
void Delete(int l,int r){
    Splay(root,l); Splay(tr[root].ch[1],r+1-tr[tr[root].ch[0]].sz);
    tr[tr[root].ch[1]].ch[0]=0;
    Update(tr[root].ch[1]); Update(root);
}
  • Reverse(翻转)
    要实现对[l,r]的翻转操作,可以将[l,r]对应的子树中所有节点的左右子节点交换位置,这样即可使树的中序遍历翻转。类似于线段树,我们可以使用对节点的标记和下传来完成对这棵子树的翻转。
void Reverse(int l,int r){
    Splay(root,l); Splay(tr[root].ch[1],r+1-tr[tr[root].ch[0]].sz);
    tr[tr[tr[root].ch[1]].ch[0]].flip^=1;
    Pushdown(tr[tr[root].ch[1]].ch[0]);
}
  • Pushdown(下传)
void Pushdown(int k){
    if(tr[k].flip){ //序列翻转标记下传
        tr[k].flip=0;
        swap(tr[k].ch[0],tr[k].ch[1]);
        tr[tr[k].ch[0]].flip^=1;
        tr[tr[k].ch[1]].flip^=1;
    }
}

推荐题目

BZOJ 1014 3223 3224 1251 1500 1503 1507 3506

Treap和Splay学习小结 最近真的是花了很大的力气来学习平衡树的内容,因为之前在弄偏序的时候提到了平衡树的内容,真的是开了一个大坑啊。 先说说treap吧,网上的资料很多,描述的也很详细,我就不细说了,这里简单的谈谈我的看法,treap就是在二叉树的基础上加了一个随机域来保证堆的性质 这样可以把树的高度维护到期望的logn级别,其他的就是一棵二叉排序树,并没有什么特别的。 我实现了指针版和数组版两种,但是说实话,在写 阅读详情

相关推荐

Splay学习笔记,每个操作都会执行splay。

文章目录前言平衡树Zig和Zag引入splay操作 前言 之前学了fhq—Treap,一种靠分裂与合并维护平衡的一种树,期望复杂度是logn,常数也较大。Treap也有带旋转版本的,但是为了早日学会LCT还是先学Splay。也建议初学者先学不带旋转的平衡树,当然还有更简单的替罪羊树也可以先学。先借简单的来了解为什么要这样做。然后学更难的就跟好理解了。 平衡树 BST(二叉搜索树)的缺点是容易被卡成链,所以我们想要通过某种方法来使它的树高不那么任意被卡。我理解的平衡树就是为了使BST保持平衡,即树的高度期望是

xuxiaobo1234的博客 566

细究平衡树Splay(伸展树)的具体过程(绝对详细!!!!)

前言: 作者的splay写法主要受到https://www.luogu.org/blog/tiger0132/slay-notes这篇文章的影响,所以代码实现基本重复,这里主要把那篇文章中没讲清楚的地方详细讲讲 作者水平有限,可能部分描述有误,欢迎指出! 另外作者码风略丑,见谅QWQ Tips:本文的Splay不含维护区间的方法,以后会另开文章介绍 ______________...

ZCL746438327的博客 582

tiktok算法协议研究

经过上述分析,可以确定目标字符串来源于一段 JSON 数据,而这段 JSON 数据来自于一个经过加密的本地文件。对字符串 "sdi_v2" 进行 SHA-1 计算,得到 20 字节的结果;将第一步得到的数据进行MD5计算,生成16字节的结果;将第二步的结果转换为十六进制字符串,从而得到 32 字节的密钥。写这种算法分析的帖子真的是太无聊了,就先分析到这里吧,后续有机会再来谈下被加密的本地文件是怎么来的!!自我感觉TT的算法并不难,就是量太大了,所以我想问问有没有感兴趣的朋友来一起分析,欢迎联系。

2503_90751938的博客 2575

Splay的基本操作(插入/删除,查询)

Splay的基本操作(插入/删除,查询) 概述 这是一棵二叉查找树 让频繁访问的节点尽量靠近根 将查询,插入等操作的点"旋转"至根 树的高度均摊为$log_n$ 变量 int root, tot; // root为当前树根(与0相连), tot是最大的编号 struct Snode { int ch[2], fa, val, cnt, size; /* ch[0]...

weixin_30666401的博客 1185

NSGA-Ⅱ算法:从原理到实战,解锁多目标优化难题

本文深入解析NSGA-Ⅱ算法在多目标优化中的应用,从原理到实战全面覆盖。通过快速非支配排序、精英策略和拥挤度比较三大创新,NSGA-Ⅱ有效解决了传统算法的效率与多样性问题。结合工业案例展示其在注塑工艺优化中的显著效果,为工程师提供实用解决方案。

weixin_29207149的博客 367

图像去雾新思路:手把手教你复现DEA-Net中的“细节增强卷积”与PyTorch实现

本文详细解析了DEA-Net中的'细节增强卷积'(DEConv)与PyTorch实现,通过多分支差分卷积和重参数化技术,显著提升单图像去雾效果。文章从数学原理到代码实现,手把手指导复现这一创新架构,帮助开发者在保持轻量化的同时实现41dB以上的PSNR指标,适用于自动驾驶、遥感监测等关键领域。

weixin_30323631的博客 505

c++算法之 - Splay树

Splay树是一种自平衡二叉搜索树,通过"伸展"操作将访问节点移至根节点,在均摊O(logn)时间内完成操作。其核心是旋转和伸展操作,包括三种旋转组合(Zig、Zig-Zig、Zig-Zag)来调整树结构。支持插入、查找、删除等基本操作,并能高效处理区间操作(如翻转)。相比AVL树和红黑树,Splay树无需存储平衡信息,代码更简洁,特别适合需要频繁调整的动态序列维护场景。通过局部性原理优化性能,使频繁访问的节点靠近根部,适用于文本编辑器、排名查询等应用。

巴巴博一巴巴博一巴巴博一 1023

【推荐100个unity插件】unity实现交互式火焰 —— Ignis

Ignis是一款Unity互动式消防系统插件,可轻松将物体转换为可燃物。支持固体、植被、蒙皮网格和地形树木等多种对象类型,提供火焰蔓延、熄灭等效果。安装需通过Unity Package Manager添加Visual Effects Graph,并按照指引转换目标物体材质。使用盒型碰撞体或网格计算燃烧区域,可自定义火焰参数和视觉效果。内置多种转换选项,如Flammable Vegetation、Flammable Skinned Mesh等,适用于不同场景需求。注意使用前需备份材质和地形数据,并提供性能优化

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2236

splay 学习笔记

splay 核心函数splay:每次访问一个节点,都把该节点转到根 (包括插入/查找/操作) 思想:对于访问频率较高的节点,使其处于根节点附近,从而保证log复杂度 splay可以维护中序遍历是有序序列 也可维护 中序遍历是当前操作后的序列 AcWing 2437. Splay P1486 [NOI2004] 郁闷的出纳员 const int N=1e5+10; struct node{ int s[2],fa,v; //son,fa,val int sz,tag; //flag懒标记 }t[N];

cym_的博客 235

lammps案例:堆垛层错能的计算

大家好,我是小马老师。 本文介绍如何使用lammps计算晶体的堆垛层错能。 正常晶体中的原子按照一定的规律排列,原子面按ABCABC……的顺序排列,如下图所示: 当某个原子面被抽出后会形成堆垛层错,如图中的蓝色原子层被抽出,原子面排列变为ABCBCA……: 可通过计算堆垛层错能形成前后的能量差计算堆垛层错能,计算公式为: E0为初始能量 Ef为删除一个原子面后的能量 A为界面面积 下面分享一个lammps计算堆垛层错能的in代码,本代码由Richard Glaze完成,本文稍作修改并进行了注释,以供初

lammps_jiayou的博客 5435

20.Labview使用子vi进行VI间的数据传递详解(模块化)

子VI(模块化)题主在题注中也提到, 子VI的建立只是为了减少程序的负担,那么我们当使用子VI的时候首先就要明确什么是子VI?什么样的程序可以作为子VI?首先我们来看NI官方给的定义,具体说明如下图所示:题主已经将重点画出来了,在官方的解释中将子VI定义为了模块化,大家可以看到创建模块化子VI的特点在于减少代码重复工作优化了程序的框架结构。把一个代码打包,需要的时候就拎出来让他处理处理,不需要的时候就让它躺在我的列表里就行了也不占用运行空间。那么创建子VI需要需要注意以下几点:①任何一个程序。

关注我,更多技术问题欢迎私聊~ 3516

Splay学习——我用splay打排序

Splay 学习——我用Splay打排序 Description 给出N个数,你的任务就是把这n个数从小到大排序_ Input 第一行一个整数,N(1<=n<=200000),表示有N个数 接下来有N行,每行一个数 Output 输出N行,表示已经排序的N个数 Sample Input 5 2 3 1 4 5 Sample Output 1 2 3 4 5 这一题相...

cjy_12的博客 238

【WRF工具】WRF Domain Wizard第一期:软件下载及安装

【WRF工具介绍】WRF Domain Wizard-确定模拟区域

WW、forever的博客 2918

splay学习报告

省选将至,慌得一批,hale赶紧去学了学splay,防止被打爆,虽说一定会被打爆的 不过这玩意是真的恶心,hale花了三个中午去搞掉他 一点点自己的理解啦,嘤嘤嘤 emmm,废话少说进入正题 一 。啥是平衡树? 根据百度百科上面说的: 平衡树,即平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,...

weixin_30807779的博客 63

C#串口通信从入门到精通(7)——整数/浮点数与二进制、八进制、十六进制之间的转换与C#实现

本文详细介绍由博主开发的DataConvert串口通信帮助类的用法,该帮助类涵盖了串口通信领域所有的数据转换方法,帮助大家快速编写串口通信程序!

qq_34059233的博客 2879

计算机控制技术及应用

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

splay学习笔记

以洛谷上的模板题为例,学习一下splay。暂时还不会区间操作。 1.插入一个数 从根节点开始找左儿子比当前的值小,右儿子比当前的值大。 如果当前插入的数已经存在我们就在cnt域上加1。 否则的话我们就要新建一个节点,同时如果当前节点不是根节点我们就要把更新当前节点的父亲节点的儿子。 插入后将当前节点splay到根节点,维护树的形态。 2.splay 目的是将某个节点旋转到目标节点。 ...

1999 236

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Splay学习笔记

Splay学习笔记

He_ttt的博客 674

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

【学习笔记】Splay

模板题链接 1、引入 一种二叉树,这棵树满足任意一个节点,它的左儿子的权值<自己的权值<右儿子的权值 这种树叫做二叉查找树,这个概念应该在初赛中见过了吧 Splay就是利用这个结构来实现的 2、变量 模板题的7大变量 sz:表示当前节点个数 rt:表示当前根节点的编号 f[x]:表示编号x节点的父亲的编号 key[x]:表示编号为 ...

ModestCoder_的博客 8716

splay学习总结

Splay(伸展树) 学习总结:   理解: Splay是一种平衡二叉排序树, 复杂度均摊log n。   单点操作Splay要点: 1、动态内存静态化 实现:(内存池回收分配): template struct memorypool { T buf[size], *tail, *st[size]; int top; memorypool() : top(0)

scarlyw的博客 505

zkw Splay学习笔记

最近。。 最近心里颇不平静。 最近花了三天时间学了zkw Splay,发现这玩意儿真TM难写;加上各种Code Trick也还是写了好久,还有各种错误,一直在炸。 一些心得: ①维护size时不需要考虑太多东西,只需要改变孩子指针后直接用孩子的size维护即可,注意要在两个地方维护: 旋转的时候维护; 翻转子树链表的时候维护。 ②zkw Splay中左临时树是一些没有右孩子子树的节点,然后。。为了方便(真的方便么。。),我们可以一开始用每棵子树的右儿子存储它的父节点,然后再把根表反转。 反转真是一

TA 1478

关于Splay的学习感受

                                        【关于Splay】 之前记得五月份听过一次外省金牌选手讲过一次,然后七月份又讲过一次,但本人脑子比较笨,当时完全听得一脸懵逼啊,练了两个月确实不一样,现在谈一下学习Splay的一些感受。 首先欲知Splay为何物,不得不先讲讲它的祖宗:二叉查找树,即BST(Binary Search Tree),关于二叉查找树,...

Michael_GLF的博客 365

splay学习

一个神奇的数据结构,可以搞来搞去,还很快? 他的优化就是每次询问一个点的时候,就暴力吧这个点更新为根(用tarjan)给出的更新方式,就可以做到n次操作,平摊下来每次的复杂度是logn,证明的话请见 大牛博客 我还是抱着一定的怀疑的,每次暴力更新,真的不会出问题,然后就去找了一个模板题,结果,真的没有出问题,emmmm,太强了,,, hdu 1754 #include&amp;amp;amp;amp;lt;bits/st...

zstu_zy的博客 246

Splay初学习

例题传送门 听YZ哥哥说Splay是一种很神奇的数据结构,所以学习了一下它的最基本操作。O(1)的Spaly。 伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(logn)内完成插入、查找和删除操作。它由丹尼尔·斯立特Daniel Sleator和罗伯特·恩卓·塔扬Robert Endre Tarjan在1985年发明的。 在伸展树上的一般操作都基于伸展操...

a309773041的博客 102
上一篇: BZOJ 1552 [Cerc2007]robotic sort
下一篇: UVa 11212 Editing a Book
Zero_Just_Me
博客等级 码龄14年 3粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值