Splay 树简介

【Splay 树简介】
Treap 树解决平衡的办法是给每个结点加上一个随机的优先级,实现概率上的平衡。Splay 树直接用旋转调整树的形态,通过旋转改善树的平衡性。计算量小,效果好。
● Splay 树的旋转主要分为“
单旋”和“双旋”。
所谓“单旋”,即把结点 x 与它的父结点交换位置,使结点 x 上升一层。“单旋”不会减少树的层数,对改善平衡性没有帮助。根据旋转方向,“单旋”又分为
左旋zag)与右旋zig)。
所谓“双旋”,即两次“单旋”。“双旋”同时旋转
结点 x,父结点 f 及祖父结点 g 等3个结点,能改善平衡性。“双旋”又分为“一字旋”与“之字旋”。
● Splay 树的旋转示意图


 



 


Splay 树的基本操作是把结点旋转到树的根部,这样下次访问它时,只需查一次就 OK 了。
● Splay 树是
动态树(LCT,Link Cut Tree)与树链剖分的基础。
● Splay 树
曾经最常使用的 BST。不过,现在经常使用 FHQ Treap 树实现很多传统的 Splay 树的题目。因为,FHQ Treap 树代码更容易写,效率也很高,且可做持久化

【Splay 树算法模板】
洛谷 P6136 代码:https://www.luogu.com.cn/problem/P6136

#include<bits/stdc++.h>
using namespace std;

const int maxn=1.1e6+5;
const int inf=(1<<30)+5;

struct Node {
    int ch[2];
    int p,v;
    int size;
    int cnt;
} tr[maxn];

int root,idx;

void pushup(int u) {
    tr[u].size=tr[tr[u].ch[0]].size+tr[tr[u].ch[1]].size+tr[u].cnt;
}

void rotate(int x) {
    int y=tr[x].p;
    int z=tr[y].p;
    int k=(tr[y].ch[1]==x);

    tr[y].ch[k]=tr[x].ch[k^1],tr[tr[x].ch[k^1]].p=y;
    tr[x].ch[k^1]=y,tr[y].p=x;
    tr[z].ch[tr[z].ch[1]==y]=x,tr[x].p=z;

    pushup(y);
    pushup(x);
}

void splay(int x, int k) {
    while(tr[x].p!=k) {
        int y=tr[x].p;
        int z=tr[y].p;

        if(z!=k) {
            if((tr[z].ch[1]==y) ^ (tr[y].ch[1]==x)) rotate(x);
            else rotate(y);
        }

        rotate(x);
    }

    if(!k) root=x;
}

void insert(int x) {
    int u=root, p=0;
    while(u && tr[u].v!=x) {
        p=u;
        u=tr[u].ch[x>tr[u].v];
    }
    if(u) tr[u].cnt++;
    else {
        u=++idx;
        if(p) tr[p].ch[x>tr[p].v]=u;
        tr[u].p=p;
        tr[u].v=x;
        tr[u].size=1;
        tr[u].cnt=1;
    }
    splay(u,0);
}

void find(int x) {
    int u=root;
    while(tr[u].ch[x>tr[u].v] && tr[u].v!=x) u=tr[u].ch[x>tr[u].v];
    splay(u,0);
}

int get_pre(int x) {
    find(x);
    if(tr[root].v<x) return root;
    int u=tr[root].ch[0];
    while(tr[u].ch[1]) u=tr[u].ch[1];
    splay(u,0);
    return u;
}

int get_suc(int x) {
    find(x);
    if(tr[root].v>x) return root;
    int u=tr[root].ch[1];
    while(tr[u].ch[0]) u=tr[u].ch[0];
    splay(u,0);
    return u;
}

void remove(int x) {
    int pre=get_pre(x);
    int suc=get_suc(x);

    splay(pre,0);
    splay(suc,pre);

    int del=tr[suc].ch[0];
    if(tr[del].cnt>1) tr[del].cnt--,splay(del,0);
    else tr[suc].ch[0]=0, splay(suc,0);
}

int get_rank_by_key(int x) {
    insert(x);
    int ans=tr[tr[root].ch[0]].size;
    remove(x);
    return ans;
}

int get_key_by_rank(int k) {
    int u=root;
    while(true) {
        if(k<=tr[tr[u].ch[0]].size) u=tr[u].ch[0];
        else if(k<=tr[tr[u].ch[0]].size+tr[u].cnt) break;
        else k-=tr[tr[u].ch[0]].size+tr[u].cnt, u=tr[u].ch[1];
    }
    splay(u,0);
    return tr[u].v;
}

int main() {
    insert(-inf);
    insert(inf);

    int n,T;
    cin>>n>>T;
    for(int i=1; i<=n; i++) {
        int x;
        cin>>x;
        insert(x);
    }

    int ans=0, last=0;

    while(T--) {
        int op,x;
        cin>>op>>x;
        x^=last;
        if(op==1) insert(x);
        else if(op==2) remove(x);
        else if(op==3) ans^=(last=get_rank_by_key(x));
        else if(op==4) ans^=(last=get_key_by_rank(x+1));
        else if(op==5) ans^=(last=tr[get_pre(x)].v);
        else ans^=(last=tr[get_suc(x)].v);
    }

    cout<<ans<<endl;

    return 0;
}

/*
in:
6 7
1 1 4 5 1 4
2 1
1 9
4 1
5 8
3 13
6 7
1 4

out:
6
*/



【参考文献】
https://www.luogu.com.cn/problem/P6136
https://blog.csdn.net/SunnyYuanJiawei/article/details/129836238
https://www.cnblogs.com/baijian0212/p/splay.html
https://www.acwing.com/solution/content/50494/
https://blog.csdn.net/hnjzsyjyj/article/details/134728992
https://blog.csdn.net/hnjzsyjyj/article/details/120380473
https://zhuanlan.zhihu.com/p/348797577







 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/597554.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于52单片机的AS608指纹密码锁电路原理图+源程序+PCB实物制作

目录 1、前言 2、实物图 3、PCB图 4、原理图 5、程序 资料下载地址&#xff1a;基于52单片机的AS608指纹密码锁电路原理图源程序PCB实物制作 1、前言 这是一个基于AS608STC89C52单片机的指纹识别和键盘密码锁。 里面包括程序&#xff0c;原理图&#xff0c;pcb图和实…

OpenNJet:云原生技术中的创新者与实践者

目录 引言OpenNJet介绍OpenNJet优势1. 性能无损动态配置2. 灵活的CoPilot框架3. 支持HTTP/34. 支持国密5. 企业级应用6. 高效安全 OpenNJet 编译与安装环境准备编译环境配置配置yum源yum 安装软件包创建符号连接修改 ld.so.conf 配置 编译代码 部署 WEB SERVER配置OpenNJet部署…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-13-按键实验

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

FTP协议与工作原理

一、FTP协议 FTP&#xff08;FileTransferProtocol&#xff09;文件传输协议&#xff1a;用于Internet上的控制文件的双向传输&#xff0c;是一个应用程序&#xff08;Application&#xff09;。基于不同的操作系统有不同的FTP应用程序&#xff0c;而所有这些应用程序都遵守同…

计算机网络【应用层】邮件和DNS

文章目录 电子邮件DNSDNS提供的服务&#xff1a;域名分级域名解析流程DNS资源记录DNS服务器类型 电子邮件 使用SMTP协议发送邮件之前&#xff0c;需要将二进制多媒体数据编码为ASCII码SMTP一般不使用中间邮件服务器发送邮件&#xff0c;如果收件服务器没开机&#xff0c;那么会…

解决jar包中没有主清单目录的问题

文章目录 解决jar包中没有主清单目录的问题问题描述环境描述方法一 | 阿里巴巴构造器的通用解决方案方式二 | 指定MANIFEST.MF路径 解决jar包中没有主清单目录的问题 问题描述 很简单可能很多人都遇到过&#xff0c;maven项目打成jar包后执行报错&#xff1a;jar包中没有主清单…

在模方中已经选好水岸线了,但是点处理瓦块的时候还是提示水岸线没选

答&#xff1a;能部分位置不闭合&#xff0c;双击右键闭合一下&#xff0c;可以强行闭合缺口。 模方是一款针对实景三维模型的冗余碎片、水面残缺、道路不平、标牌破损、纹理拉伸模糊等共性问题研发的实景三维模型修复编辑软件。模方4.1新增自动单体化建模功能&#xff0c;支持…

高情商回复(不是)

背景介绍 在抖音上有这样的视频&#xff0c;视频就是一张图&#xff0c;图上问了一个问题&#xff1a;饭局上&#xff0c;你去帮领导盛饭&#xff0c;领导接过后说&#xff1a;‘盛这么多&#xff0c;喂猪呢&#xff1f;’咋回&#xff1f; 底下有一个搞笑评论&#xff1a;猪可…

迅雷永久破解

链接&#xff1a;https://pan.baidu.com/s/1ZGb1ljTPPG3NFsI8ghhWbA?pwdok7s 下载后解压 以管理员身份运行绿化.bat&#xff0c;会自动生成快捷方式&#xff0c;如果没有可以在program中运行Thunder.exe

UDP如何端口映射?

UDP端口映射是一种网络技术&#xff0c;通过它可以实现在异地组网的情况下&#xff0c;不暴露在公网上&#xff0c;通过私有通道传输数据&#xff0c;并对数据进行安全加密&#xff0c;以保障数据的安全性。这项技术在如今日益复杂和危险的网络环境中显得尤为重要。 UDP&#x…

Rust 适合哪些场景?

目录 二、Rust 适合哪些场景&#xff1f; 三、Rust 社区的发展趋势如何&#xff1f; 四、Rust 快速搭建一个WebServer服务器 一、Rust是什么&#xff1f; Rust是一门赋予每个人构建可靠且高效软件能力的语言。 Rust 程序设计语言 一门帮助每个人构建可靠且高效软件的语言。…

tomcat-以服务的方式重启tomcat

背景 双击tomcat的bin目录下面的startup.bat&#xff0c;会留下一个cmd的窗口&#xff0c;很不优雅 使用service服务的方式启动&#xff0c;并且设置为自动启动 找到tomcat的bin目录输入cmd&#xff0c;按Enter&#xff0c;进入命令行界面。执行“service.bat install” 。&…

详解嵌入式MCU运行时分配的stack和heap

目录 概述 1 认识stack和heap 1.1 栈区&#xff08;stack&#xff09; 1.2 堆区&#xff08;heap&#xff09; 2 stack和heap的区别 2.1 管理方式的不同 2.2 空间大小不同 2.3 产生碎片不同 2.4 增长方式不同 2.5 分配方式不同 2.6 分配效率不同 3 确定stack和heap…

架构师:搭建Spring Security、OAuth2和JWT 的安全认证框架

1、简述 Spring Security 是 Spring 生态系统中的一个强大的安全框架,用于实现身份验证和授权。结合 OAuth2 和 JWT 技术,可以构建一个安全可靠的认证体系,本文将介绍如何在 Spring Boot 中配置并使用这三种技术实现安全认证,并分析它们的优点。 2、Spring Security Spri…

Linux基础04-Linux中目录和文件都能操作的命令

前面两节我们分别学习了目录操作命令和文件操作命令&#xff0c;那么有没有一些既可以操作目录&#xff0c;又可以操作文件的命令呢&#xff1f; 这样我们就不需要记住两套命令了。 其实还真有&#xff0c;今天这一章就带大家学习Linux中目录和文件都能操作的命令 最近无意间获…

深度学习之DCGAN

目录 须知 转置卷积 DCGAN 什么是DCGAN 生成器代码 判别器代码 补充知识 LeakyReLU&#xff08;x&#xff09; torch.nn.Dropout torch.nn.Dropout2d DCGAN完整代码 运行结果 图形显示 须知 在讲解DCGAN之前我们首先要了解转置卷积和GAN 关于GAN在这片博客中已经很…

GraphGPT——图结构数据的新语言模型

在人工智能的浪潮中&#xff0c;图神经网络&#xff08;GNNs&#xff09;已经成为理解和分析图结构数据的强大工具。然而&#xff0c;GNNs在面对未标记数据时&#xff0c;其泛化能力往往受限。为了突破这一局限&#xff0c;研究者们提出了GraphGPT&#xff0c;这是一种为大语言…

ASP.NET MVC(二) HtmlHelper

强类型 》》》 Form Html.Action() 执行一个Action&#xff0c;并返回html字符串。 Html.ActionLink() 生成一个超链接。 》》》 htmlhelper 扩展方法 /// 扩展方法 三要素 静态类静态方法this 》》》》上面需要引入命名空间&#xff0c; 》》》 不需要引入命名空间 pu…

每日OJ题_DFS解决FloodFill⑥_力扣529. 扫雷游戏

目录 力扣529. 扫雷游戏 解析代码 力扣529. 扫雷游戏 529. 扫雷游戏 难度 中等 让我们一起来玩扫雷游戏&#xff01; 给你一个大小为 m x n 二维字符矩阵 board &#xff0c;表示扫雷游戏的盘面&#xff0c;其中&#xff1a; M 代表一个 未挖出的 地雷&#xff0c;E 代表…

计算机系列之数据库技术

13、数据库技术&#xff08;重点、考点&#xff09; 1、三级模式-两级映像&#xff08;考点&#xff09; 内模式&#xff1a;管理如何存储物理的数据&#xff0c;对应具体物理存储文件。 **模式&#xff1a;**又称为概念模式&#xff0c;就是我们通常使用的基本表&#xff0c…