BST,Treap学习随笔

news/2026/1/17 11:14:11/文章来源:https://www.cnblogs.com/xwy114514/p/19495409

BST,Treap学习随笔

0 前言

学习随笔

1 BST

二叉查找树

1.1 性质

对于一个点来说

左子树中所有权值均小于当前点权值小于右子树中所有点权值

还有一个神奇的性质:

中序遍历一下 发现天然有序

上图中序遍历即为1,2,3,4,5,6,7,8,9,10,11

1.2 支持基本操作

插入(\(logn\))(最坏\(n\)

删除(\(logn\))(最坏\(n\)

找v在树上大小排第几(\(logn\))(最坏\(n\)

求第k小(\(logn\))(最坏\(n\)

求前驱(权值严格小于v的最大值)(\(logn\))(最坏\(n\)

求后继(全职严格大于v的最小值)(\(logn\))(最坏\(n\)

(因为对于同一棵树满足BST性质的形状有很多种,在一些数据下树会变成一条链,从而使操作都退化到\(O(n)\)

1.3 维护

因为Treap为BST升级版,基本操作都一样,所以直接看Treap的维护吧

2 Treap

杂交数据结构

Treap=BST(二叉查找树)+Heap(堆)

2.1 性质

既满足BST(点权)

又满足Heap(我们给点附的优先值,这里优先值是rand出来的)(可以有效避免退化成一条链的情况)

优先值满足大根堆性质(小根堆也行 只要是个堆即可)

2.2 支持操作

插入(\(logn\)

删除(\(logn\)

找v在树上大小排第几(\(logn\)

求第k小(\(logn\)

求前驱(权值严格小于v的最大值)(\(logn\)

求后继(全职严格大于v的最小值)(\(logn\)

(因为有了rand出的优先级 树在没有被神秘宇宙射线影响的情况下是不会退化到链的)

2.3 维护

2.3.1 点的信息

struct node{int l,r,val,siz,cnt;//左节点,右节点,权值,子树大小(含自己),自己有几个unsigned pri;//随机生成的优先值
}a[N];

2.3.2 插入

2.3.2.1 zig,zag

发现严重问题:如何同时维护两个性质

我们左思右想 决定先满足其中一个性质

先满足BST性质

首先在原树上找到应该放当前权值的位置

然后需要在不破坏当前BST性质的情况下使rand出的优先值满足Heap

于是发明出zig(右旋),zag(左旋)操作

对应不同需交换情况

/*Y                X/        =>     /  \X         zig   A    Y /  \                  /
A    B                BY                    X\          =>     /  \X         zag   Y    B/   \              \
A    B               A*/

发现原本的BST性质没有被破坏且X,Y父子关系还交换了

这就很像Heap中的挂在叶子节点一直往上交换的操作

size更新的时候需注意:我们在插入重复值时是直接把当前权值对应点中的cnt++

因此计算size时需要加上自己的cnt

void siz_update(int u){if(!u)return;a[u].siz=a[a[u].l].siz+a[a[u].r].siz+a[u].cnt;//加上自己的个数
}void zig(int &y){//右旋  将y与y的左子树交换//& 是为了方便直接将当前访问的y的值改变为x int x=a[y].l;//y的左子树a[y].l=a[x].r;//将x的右子树挂在y的左子树上a[x].r=y;//将y挂在x的左子树上siz_update(y);//先更新y的size(因为y现在在x下面)siz_update(x);//再更新x的sizey=x;
}void zag(int &y){//左旋 将y与y的右子树交换int x=a[y].r;//y的右子树a[y].r=a[x].l;//将x的左子树挂在y的右子树上a[x].l=y;//将y挂在x的左子树上siz_update(y);//更新sizesiz_update(x);y=x;
}

2.3.2.2 Insert

有了zig,zag我们就可以愉快地insert了

int add(int v){a[++tot]={0,0,v,1,1,rnd()};//l,r初始化为0 表示没有左节点和右节点 //val=v//siz和cnt初始化为1//pri优先级rand一下return tot;
}
void Insert(int &rt,int v){//& 也是方便直接改值if(!rt){//扫到叶子节点了rt=add(v);siz_update(rt);//别忘了更新大小return;}if(v==a[rt].val){//有这个权值了a[rt].cnt++;//直接加siz_update(rt);//依旧别忘了更新return;}else if(v<a[rt].val){//比当前权值小 说明还要往左走Insert(a[rt].l,v);//以左节点为根继续维护if(a[a[rt].l].pri<a[rt].pri){//维护Heap的性质 这里只可能是左节点有问题zig(rt);//右旋交换}}else if(v>a[rt].val){//同上Insert(a[rt].r,v);if(a[a[rt].r].pri<a[rt].pri){zag(rt);}}siz_update(rt);//别忘了更新
}

2.3.3 删除

void Erase(int &rt,int v){if(!rt){//找到了 返回return;}if(v==a[rt].val){//找到了if(a[rt].cnt>1){//还有 直接减a[rt].cnt--;siz_update(rt);//别忘了更新!return;}else if(!a[rt].l&&!a[rt].r){//交换到了叶子节点就可以直接删除了rt=0;//直接一直返回return;}else if(!a[rt].r||(a[rt].l&&a[a[rt].l].pri>a[a[rt].r].pri)){//没有右子树 或者有左子树并且左子树优先级比右子树优先级大zig(rt);//右旋上来Erase(a[rt].r,v);//交换过后原本要删的点在右边}else if(!a[rt].l||(a[rt].r&&a[a[rt].r].pri>a[a[rt].l].pri)){//没有左子树 或者有右子树并且右子树优先级比左子树优先级大zag(rt);//左旋上来Erase(a[rt].l,v);//交换后原本要删的点在左边}}else if(v<a[rt].val){//找左子树Erase(a[rt].l,v);}else if(v>a[rt].val){//找右子树Erase(a[rt].r,v);}siz_update(rt);//更新!!!!!!
}

2.3.4 查找排名

int Rank(int rt,int v){if(!rt)return 1;//空树则自己就是第一if(v==a[rt].val){//找到了return a[a[rt].l].siz+1;//左子树中所有一定比自己小 加一就是排名}else if(v<a[rt].val){return Rank(a[rt].l,v);//一定在左子树中排名}else{return a[a[rt].l].siz+a[rt].cnt+Rank(a[rt].r,v);//左子树大小加中间点个数再加右子树中排名}
}

2.3.5 找第k小

int kth(int rt,int k){if(!rt)return -1;//没找到if(k<=a[a[rt].l].siz){//如果还没左子树大小大 说明在左子树中return kth(a[rt].l,k);//递归左子树}k-=a[a[rt].l].siz;//如果比左子树大就减去if(k<=a[rt].cnt){//剩下的比中间点个数小 说明就是中间点return a[rt].val;}k-=a[rt].cnt;//还大 减去return kth(a[rt].r,k);//递归右子树
}

2.3.6 找前驱/后继

int ask_pre(int rt,int v){//前驱int res=-INF;//初始化为极小值while(rt){//一直找到底才是严格小于他的最大值if(v<=a[rt].val){//大了rt=a[rt].l;//往左边找小的}else{res=a[rt].val;//够了rt=a[rt].r;//往右边找有没有正在比v小的情况下更大的值}}return res;
}int ask_nex(int rt,int v){//后继  细节同上int res=INF;while(rt){if(v>=a[rt].val){rt=a[rt].r;}else{res=a[rt].val;rt=a[rt].l;}}return res;
}

2.4 模板题

【模板】普通平衡树

附上代码

#include<bits/stdc++.h>
using namespace std;
#define int long longconst int N=2e5+5;
const int INF=0x3f3f3f3f3f3f3f;static unsigned seed=(unsigned)chrono::steady_clock::now().time_since_epoch().count();
unsigned rnd(){seed^=seed<<12,seed^=seed>>5,seed^=seed<<11;return seed;
}
struct node{int l,r,val,siz,cnt;unsigned pri;
}a[N];
int tot=0;
int root=0;
int n;int add(int v){a[++tot]={0,0,v,1,1,rnd()};return tot;
}void siz_update(int u){if(!u)return;a[u].siz=a[a[u].l].siz+a[a[u].r].siz+a[u].cnt;}void zig(int &y){int x=a[y].l;a[y].l=a[x].r;a[x].r=y;siz_update(y);siz_update(x);y=x;
}void zag(int &y){int x=a[y].r;a[y].r=a[x].l;a[x].l=y;siz_update(y);siz_update(x);	y=x;
}void Insert(int &rt,int v){if(!rt){rt=add(v);siz_update(rt);return;}if(v==a[rt].val){a[rt].cnt++;siz_update(rt);return;}else if(v<a[rt].val){Insert(a[rt].l,v);if(a[a[rt].l].pri<a[rt].pri){zig(rt);}}else if(v>a[rt].val){Insert(a[rt].r,v);if(a[a[rt].r].pri<a[rt].pri){zag(rt);}}siz_update(rt);
}void Erase(int &rt,int v){if(!rt){return;}if(v==a[rt].val){if(a[rt].cnt>1){a[rt].cnt--;siz_update(rt);return;}else if(!a[rt].l&&!a[rt].r){rt=0;return;}else if(!a[rt].r||(a[rt].l&&a[a[rt].l].pri>a[a[rt].r].pri)){zig(rt);Erase(a[rt].r,v);}else if(!a[rt].l||(a[rt].r&&a[a[rt].r].pri>a[a[rt].l].pri)){zag(rt);Erase(a[rt].l,v);}}else if(v<a[rt].val){Erase(a[rt].l,v);}else if(v>a[rt].val){Erase(a[rt].r,v);}siz_update(rt);
}int Rank(int rt,int v){if(!rt)return 1;if(v==a[rt].val){return a[a[rt].l].siz+1;}else if(v<a[rt].val){return Rank(a[rt].l,v);}else{return a[a[rt].l].siz+a[rt].cnt+Rank(a[rt].r,v);}
}int kth(int rt,int k){if(!rt)return -1;if(k<=a[a[rt].l].siz){return kth(a[rt].l,k);}k-=a[a[rt].l].siz;if(k<=a[rt].cnt){return a[rt].val;}k-=a[rt].cnt;return kth(a[rt].r,k);
}int ask_pre(int rt,int v){int res=-INF;while(rt){if(v<=a[rt].val){rt=a[rt].l;}else{res=a[rt].val;rt=a[rt].r;}}return res;
}int ask_nex(int rt,int v){int res=INF;while(rt){if(v>=a[rt].val){rt=a[rt].r;}else{res=a[rt].val;rt=a[rt].l;}}return res;
}signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n;while(n--){int op,x;cin>>op>>x;if(op==1){Insert(root,x);}else if(op==2){Erase(root,x);}else if(op==3){cout<<Rank(root,x)<<endl;}else if(op==4){cout<<kth(root,x)<<endl;}else if(op==5){cout<<ask_pre(root,x)<<endl;}else if(op==6){cout<<ask_nex(root,x)<<endl;}}return 0;
}

完结撒花🎉🎉🎉

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

南京市浦口江宁六合溧水高淳区英语雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 老周说教育

经教育部教育考试院认证、全国雅思教学质量监测中心联合指导,参照《2024-2025中国大陆雅思成绩大数据报告》核心标准,结合南京市浦口区、江宁区、六合区、溧水区、高淳区4500份考生调研问卷、62家教育机构全维度实测…

Qwen3-1.7B政务问答系统:某市大数据局部署实战案例

Qwen3-1.7B政务问答系统&#xff1a;某市大数据局部署实战案例 1. 背景与技术选型 随着城市治理数字化转型的加速推进&#xff0c;某市大数据管理局面临公众咨询量激增、人工响应效率低、信息检索分散等挑战。传统的FAQ系统已无法满足市民对政策解读、办事流程、公共服务等复杂…

微服务架构蓝绿部署验收测试:测试从业者的实战指南

蓝绿部署与微服务的结合‌ 在微服务架构中&#xff0c;蓝绿部署&#xff08;Blue-Green Deployment&#xff09;是一种零停机发布策略&#xff0c;通过并行运行两个相同环境&#xff08;“蓝”代表旧版本&#xff0c;“绿”代表新版本&#xff09;来实现无缝切换。这种部署方式…

2026年正规的铝合金清洗剂,清洗剂,超声波清洗剂厂家选型决策榜单 - 品牌鉴赏师

引言在工业生产中,清洗剂的使用至关重要,尤其是铝合金清洗剂和超声波清洗剂,它们广泛应用于汽车、电子、航空航天等众多领域。随着环保要求的日益严格和工业生产对清洗质量的不断提高,市场上清洗剂厂家众多,如何选…

南京市玄武秦淮建邺鼓楼栖霞雨花台区英语雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 老周说教育

经教育部教育考试院认证、全国雅思教学质量监测中心联合指导,参照《2024-2025中国大陆雅思成绩大数据报告》核心标准,结合南京市玄武区、秦淮区、建邺区、鼓楼区、栖霞区、雨花台区4000份考生调研问卷、55家教育机构…

润色后的热补丁更新业务连续性验证:测试工程师的实战指南

‌‌‌一、热补丁技术的双刃剑特性‌ 热补丁技术在追求系统零停机的同时&#xff0c;也潜藏着不容忽视的风险。行业数据显示&#xff0c;‌72%的生产环境事故源于补丁的误操作‌&#xff08;Gartner 2025&#xff09;。因此&#xff0c;一次成功的热补丁更新必须严格验证三个核…

Burp Suite Professional 2026.1 for Windows x64 - 领先的 Web 渗透测试软件

Burp Suite Professional 2026.1 for Windows x64 - 领先的 Web 渗透测试软件Burp Suite Professional 2026.1 for Windows x64 - 领先的 Web 渗透测试软件 世界排名第一的 Web 渗透测试工具包 请访问原文链接:https:…

基于SpringBoot的智能停车场管理系统源码文档部署文档代码讲解等

课题介绍 本课题旨在设计并实现一套基于SpringBoot框架的智能停车场管理系统&#xff0c;以解决传统停车场管理中车位利用率低、进出通行拥堵、收费结算繁琐、车辆管控滞后等痛点&#xff0c;助力停车场运营数字化、管控智能化升级。系统依托SpringBoot的高效开发特性与生态优势…

Microsoft SQL Server 2022 RTM GDR CU23 (2026 年 1 月安全更新 | 累计更新)

Microsoft SQL Server 2022 RTM GDR & CU23 (2026 年 1 月安全更新 | 累计更新)Microsoft SQL Server 2022 RTM GDR & CU23 (2026 年 1 月安全更新 | 累计更新) relational database management system (RDBMS…

Udemy pragmatic-system-design

Udemy pragmatic-system-designhttps://colin-scott.github.io/personal_website/research/interactive_latency.html Tutorial https://commscope1.udemy.com/course/pragmatic-system-design/learn/lecture/23340674…

Kotaemon微服务改造:拆分组件实现高可用架构升级

Kotaemon微服务改造&#xff1a;拆分组件实现高可用架构升级 1. 背景与挑战 Kotaemon 是由 Cinnamon 开发的开源项目&#xff0c;定位为一个面向文档问答&#xff08;DocQA&#xff09;场景的 RAG&#xff08;Retrieval-Augmented Generation&#xff09;前端界面。它不仅服务…

fastboot驱动中USB枚举过程的实战案例分析

fastboot驱动中USB枚举失败&#xff1f;一文看懂从硬件到协议的全链路排查你有没有遇到过这样的场景&#xff1a;设备插上电脑&#xff0c;串口打印明明写着“Entering fastboot mode…”&#xff0c;但主机却像没看见一样——设备管理器里没有新设备&#xff0c;fastboot devi…

【节点】[Integer节点]原理解析与实际应用

在Unity URP Shader Graph中,Integer节点是一个基础但功能强大的工具节点,它允许开发者在着色器程序中定义和使用整型常量。虽然着色器编程通常以浮点数运算为主,但整数在特定场景下【Unity Shader Graph 使用与特效…

Burp Suite Professional 2026.1 发布,新增功能简介

Burp Suite Professional 2026.1 发布,新增功能简介Burp Suite Professional 2026.1 发布,新增功能简介 Burp Suite Professional 2026.1 (macOS, Linux, Windows) - Web 应用安全、测试和扫描 Burp Suite Professio…

Burp Suite Professional 2026.1 for macOS x64 ARM64 - 领先的 Web 渗透测试软件

Burp Suite Professional 2026.1 for macOS x64 & ARM64 - 领先的 Web 渗透测试软件Burp Suite Professional 2026.1 for macOS x64 & ARM64 - 领先的 Web 渗透测试软件 世界排名第一的 Web 渗透测试工具包 请…

初学Prompt工程 - 教程

初学Prompt工程 - 教程2026-01-17 10:57 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font…

Apple Creator Studio 2026 发布 - 强大的创意套装 (音乐制作、视频剪辑、图像设计与办公工具)

Apple Creator Studio 2026 发布 - 强大的创意套装 (音乐制作、视频剪辑、图像设计与办公工具)Apple Creator Studio 2026 发布 - 强大的创意套装 (音乐制作、视频剪辑、图像设计与办公工具) Apple Creator Studio 登场…

制造业QMS质量管理系统推荐榜单 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2026隔音板定制厂家排名,教你如何选择好厂家 - 工业品牌热点

在城市化进程加速、噪声污染日益严峻的当下,优质的隔音材料不仅是建筑空间的静音屏障,更是守护人们生活品质与工作效率的核心保障。面对市场上品类繁杂的隔音板供应企业,如何找到兼具专业实力、可靠售后与定制能力的…