首页 > 其他分享 >「学习笔记」平衡树——splay 一

「学习笔记」平衡树——splay 一

时间:2023-06-04 20:12:10浏览次数:50  
标签:ch val int 笔记 id splay fa 平衡 节点

Splay,一种平衡树,同时也是二叉排序树,与 Treap 不同,它不需要维护堆的性质,它由 Daniel Sleator 和 Robert Tarjan(没错,tarjan,又是他)创造,伸展树是一种自调整二叉树,它会将一个节点沿着到根的路径旋转上去。
空间效率:\(O_n\)
摊平时间效率:\(O_{logn}\)
建议先学会 Treap。

存储结构

int ch[N][2],fa[N];//左孩子,右孩子,父亲 
ll val[N],siz[N],cnt[N];//点值 

数组存储,也可以用结构体。

基本操作

一、旋转

与 treap 的旋转无太大差异,只要注意更新父节点就行了,记得要更新 \(siz\)。
Splay 的旋转函数的参数,是转上去的那个数值,这里与 Treap 不同,Treap 是转下来的数值。
这里旋转一定要注意次序,明白先处理哪个,再处理哪个,否则会 RE!
一定要先处理 \(x\) 与 \(y\) 的孩子,再处理 \(x\) 与 \(y\)。

void pushup(int id)//更新siz 
{
    siz[id]=siz[ch[id][0]]+siz[ch[id][1]]+cnt[id];
}
void spin(int x)
{
    rint y=fa[x],z=fa[y],d=(ch[y][1]==x);//d 判断x是y的左孩子还是右孩子 
    ch[z][ch[z][1]==y]=x,fa[x]=z;//处理x与z的关系 
    ch[y][d]=ch[x][d^1],fa[ch[x][d^1]]=y;//处理y的孩子与x的孩子的关系 
    ch[x][d^1]=y;fa[y]=x;//处理y与x的关系 
    pushup(y);//先更新y 
    pushup(x);//在更新x 
}

二、伸展

情况一

\(x\) 要移动到父节点的位置。
image
自己懒得画了,图扒的教练的
直接旋转 \(x\) 即可。

情况二

\(x\) 点要移到到 \(g\) 或更向上的位置且 \(g\) -> \(p\) 和 \(p\) -> \(x\) 是同一方向。
image
这里要先旋转 \(p\),再旋转 \(x\)。

情况三

\(x\) 点要移到到 \(g\) 或更向上的位置且 \(g\) -> \(p\) 和 \(p\) -> \(x\) 不是是同一方向。
image
这里旋转两次 \(x\)。
其实,到这里你会发现,最后一次都是旋转 \(x\)。

void splay(int x,int goal)
{
    while(fa[x]!=goal)//判断是否已经到目标点的下边 
    {
        rint y=fa[x],z=fa[y];
        if(z!=goal)//判断是情况一还是情况二、三 
            (ch[y][0]==x)^(ch[z][0]==y)?spin(x):spin(y);
        //判断是情况二还是情况三 
        spin(x);
    }
    if(goal==0)    root=x;//如果移动到了根节点,则更新根节点 
}

三、插入节点

只要记得处理父节点就行了。

void insert(ll x)
{
    int u=root,fat=0;
    while(u&&val[u]!=x)//先向下找 
    {
        fat=u;
        u=ch[u][x>val[u]];
    }
    if(u)    cnt[u]++;
    else
    {
        u=++tot;
        if(fat)    ch[fat][x>val[fat]]=u;//如果不是根节点,更新孩子节点 
        fa[u]=fat;//插入操作 
        val[u]=x;
        siz[u]=1;
        cnt[u]=1;
    }
    splay(u,0);//每次都要伸展,避免成链 
}

四、查找结点

按照二叉排序树找到节点,然后将该节点伸展到到根节点就行了。

void find(ll x)
{
    int u=root;
    if(!u)    return;//不存在该节点,直接返回 
    while(ch[u][x>val[u]]&&x!=val[u])//找到该节点的位置 
        u=ch[u][x>val[u]];
    splay(u,0);//伸展 
}

五、查找前驱后继

先将要查找的值的位置或相邻的位置伸展到根节点,然后在左右子树中搜索。

int get(ll x,int d)//d:0找前驱 1找后继 
{
    find(x);//先伸展 
    int u=root;
    if((val[u]>x&&d)||(val[u]<x&&!d))    return u;
    //如果该节点已经符合要求,直接返回位置 
    u=ch[u][d];//找到左右子树 
    while(ch[u][d^1])    u=ch[u][d^1];
    //找左子树中最大的或右子树中最小的(关键看你找前驱还是后继) 
    return u;//返回前驱或后继的位置 
}

六、删除节点

先找到前驱和后继,将前驱伸展到根节点,将后继伸展到前驱下面,根据二叉查找树的性质,后继的左孩子就是我们要删的点,进行操作即可。

void del(ll x)
{
    int pre=get(x,0),nxt=get(x,1);//找前驱后继 
    splay(pre,0),splay(nxt,pre);//伸展 
    int id=ch[nxt][0];//要删除的点 
    if(cnt[id]>1)//如果这个数值有重复,直接--cnt即可 
    {
        --cnt[id];
        splay(id,0);//伸展 
    }
    else
    {
        ch[nxt][0]=0,fa[id]=0;//先切断联系 
        val[id]=0,cnt[id]=0,siz[id]=0;//再进行删除 
        pushup(nxt),pushup(pre);//最后更新siz 
    }
}

其他文章

平衡树——splay 二
平衡树——splay 三

标签:ch,val,int,笔记,id,splay,fa,平衡,节点
From: https://www.cnblogs.com/yifan0305/p/16468884.html

相关文章

  • 第13、14章读书笔记
    第13章密码协议导论密码协议是由协议的各个参与者之间进行一系列的消息交换组成的。主要的挑战:协议的设计者或者实现者并不能控制协议的过程。13.1角色一般交互双方定为Alice和Bob,攻击者为Eve单个实体可充当协议中的任意一方角色13.2信任信任是我们与他人进行所有往来(......
  • 单节点kafka部署笔记
    1背景因为工作中需要对接kafka,准备在测试环境中自己部署一套,考虑方便决定部署一台单点。2部署2.1scala2.1.1java环境openjdk即可,我使用的是openjdk1.82.1.2下载软件下载scala-2.12.17.tgz并解压,例如解压到/home/scala/scala-2.12.172.1.3环境变量exportSCALA_HOME......
  • (ex)BSGS/(扩展)大步小步算法 学习笔记
    (ex)BSGS/(扩展)大步小步算法学习笔记在即将暂时退役之际杀掉了P4195的毒瘤模板题,于是来写篇学习笔记。谨此为我初中三年摆烂的OI生涯画上一个句号。(距离中考还有20天!)BSGSlink求\(a^x\equivb\pmodp\)的非负整数解,其中\(a,p\)互质。算法思路我们不妨令\(t=\lceil{\sqrt{p}......
  • 「学习笔记」模运算与 BSGS 算法
    取模取模符号:\(x\bmody\),表示\(x\)除以\(y\)得到的余数。例如,\[5\bmod3=2\\7\bmod4=3\\3\bmod3=0\\\]设\(x\)为被除数,\(y\)为除数,\(z\)为余数,则\(x=k\cdoty+z,k=\lfloor\dfrac{x}{y}\rfloor\)。模运算\[\left(a+b\right......
  • flutter学习笔记(二)
    flutter一切皆widgetflutter和web前端的区别:1.js语法变成dart2.html标签变成组件widget3.flutter里没有css,只有各种widget的属性来实现样式(比如绝对定位用Stack组件来实现)fluter和web前端的相同点:1.dart语法接近js2.flutter里也可以实现flex弹性布局,用Expanded来实现(Expand......
  • 小迪安全web学习笔记(8)
    1、信息收集在安全测试中,信息收集是非常重要的一个环节,此环节的信息将影响到后续的成功几率,掌握信息的多少将决定发现漏洞机会大小,换言之决定着是否能完成目标的测试任务。也可以很直接的跟大家说:渗透测试的思路就是从信息收集这里开始。2、信息收集过程有无web 有CDN 国外请求......
  • 小迪安全web学习笔记(10)
    1、信息收集-资产信息github监控通过第三方软件监控你设定的最新漏洞信息并推送ctcms监控seo优化2、子域名挖掘3、补天漏洞响应平台用来攻击漏洞赚钱的平台。4、python脚本用来完成GitHub的监控,用信息搜集过程中得到得名称代入进脚本中运行,再下载推送得程序脚本再把它拖到相应......
  • 小迪安全web学习笔记(9)
    1、信息收集APP及其他资产APK:安卓应用程序包2、某IP无web框架下的第三方测试一阵扫描端口接口3、端口扫描工具速度:mas准确度:Nmap扫描ip用黑暗引擎:zoomeye子域名查看旁注查询4、类似域名接口查,查备案信息shodanfofa ......
  • 小迪安全web学习笔记(12)
    1、SQL注入数据库类型提交方法数据类型查询方法回显/盲注注入扩展WAF绕过防御方案2、mySQL简单注入危害:SQL注入可操控数据简易代码分析原理:通过参数传递把恶意代码传入sql语句中,让后面的代码显现出来。需要学习php、html、mySQL语句的基础知识去理解3、post注入的地方是输入账号......
  • 小迪安全web学习笔记(11)
    1、web漏洞-必懂知识点数据库的语句2、地址:网站域名、文件夹(目录)、文件参数名、参数值3、目录遍历漏洞跨目录文件的读取:/../../../文件名需要知道目录结构(怎样知道):工具扫描爬行通过网页源代码读4、漏洞等级和危害高危:SQL注入文件上传文件包含代码执行未授权访......