当前位置: 首页 > news >正文

Splay

前言

Splay是一种维护平衡二叉树的算法。虽然它常数大,而且比较难打,但Splay十分方便,而且LCT需要用到。


约定

cnticnt_icnti:节点iii的个数
valival_ivali:节点iii的权值
sizisiz_isizi:节点iii的子树大小
chi,0/1ch_{i,0/1}chi,0/1:节点iii的左右儿子
faifa_ifai节点iii的父亲
rootrootroot当前的根节点
tottottot当前的节点数量

gt(x)gt(x)gt(x):返回xxx是左儿子还是右儿子
pushup(x)pushup(x)pushup(x):更新当前子树大小

int gt(int x){return ch[fa[x]][1]==x;
}
void pt(int x){siz[x]=cnt[x]+siz[ch[x][0]]+siz[ch[x][1]];
}

基本操作

旋转操作

在这里插入图片描述

  • yyyzzz的哪个儿子,xxx就是zzz的哪个儿子
  • xxxyyy的哪个儿子,yyy就是xxx的对应儿子的兄弟
  • xxxyyy的哪个儿子,yyy的那个儿子就是xxx的对应儿子的兄弟
void rot(int x){int y=fa[x],z=fa[y],k=gt(x);ch[z][gt(y)]=x,fa[x]=z;ch[y][k]=ch[x][!k],fa[ch[y][k]]=y;ch[x][!k]=y,fa[y]=x;pt(y);pt(x);
}

伸展操作

splay(x,g)splay(x,g)splay(x,g),表示将xxx旋转到ggg下面。

我们可以一直rotrotrot,但如果xxx的父亲不是gggxxxxxx的父亲是同一边的儿子,则可以旋转父亲。先旋转父亲可以减少深度。

void splay(int x,int g=0){for(int y;fa[x]!=g;rot(x)){y=fa[x];if(fa[y]!=g) rot((gt(x)==gt(y))?y:x);}if(!g) root=x;
}

普通操作

find操作

找到值最接近xxx的点,并伸展到根。

void find(int x){if(!root) return;int u=root;while(ch[u][x>v[u]]&&x^v[u]) u=ch[u][x>v[u]];splay(u);
}

insert操作

插入值为xxx的点,需进行一下操作

  • 找到插入点的位置
  • 如果存在值为xxx的点,则加对应的cntcntcnt
  • 否则新加一个点
  • 把该节点伸展到根
void insert(int x){int u=root,fu=0;while(u&&v[u]!=x){fu=u,u=ch[u][x>v[u]];}if(u) ++cnt[u];else{u=++tot;if(fu) ch[fu][x>v[fu]]=u;fa[u]=fu;v[u]=x;cnt[u]=siz[u]=1;}splay(u);
}

前驱和后继

xxx的前驱和后继

find(x)find(x)find(x),那么前驱就是左子树中最大的一个,后继就是右子树中最小的一个。

int nxt(int x,int f){find(x);int u=root;if(v[u]>x&&f) return u;if(v[u]<x&&!f) return u;u=ch[u][f];while(ch[u][!f]) u=ch[u][!f];return u;
}

delete操作

删除值为xxx的点

首先找到xxx的前驱sucsucsucxxx的后继preprepre,然后

  • splay(pre)splay(pre)splay(pre)
  • splay(suc,pre)splay(suc,pre)splay(suc,pre)

然后sucsucsuc的左子树就是要删除的点,删除即可。

void dele(int x){int lt=nxt(x,0),nt=nxt(x,1);splay(lt);splay(nt,lt);int tx=ch[nt][0];if(cnt[tx]>1) --cnt[tx],splay(tx);else ch[nt][0]=0;
}

kth操作

找到排名为kkk的节点的权值

int kth(int k){int u=root,sn=0;for(;;){sn=ch[u][0];if(k>siz[sn]+cnt[u]) k-=siz[sn]+cnt[u],u=ch[u][1];else if(siz[sn]>=k) u=sn;else return v[u];}
}

例题

普通平衡树

对于操作1,2,4,5,6,可以用上述操作解决即可。对于操作3,可以find(x)find(x)find(x)将其置为根,然后xxx的排名就是它左子树的节点个数+1+1+1

注意为了防止splaysplaysplay出锅,要在加上两个节点∞\infty−∞-\infty。注意这两个节点对操作的影响。

#include<iostream>
#include<cstdio>
#define N 500000
using namespace std;
int root,tot,t,cnt[N],v[N],siz[N],ch[N][2],fa[N];
int gt(int x){return ch[fa[x]][1]==x;
}//Return 0 or 1 means x is the left or right son
void pt(int x){siz[x]=cnt[x]+siz[ch[x][0]]+siz[ch[x][1]];
}//Update the x
void rot(int x){int y=fa[x],z=fa[y],k=gt(x);ch[z][gt(y)]=x,fa[x]=z;ch[y][k]=ch[x][!k],fa[ch[y][k]]=y;ch[x][!k]=y,fa[y]=x;pt(y);pt(x);
}//Rotate
void splay(int x,int g=0){for(int y;fa[x]!=g;rot(x)){y=fa[x];if(fa[y]!=g) rot((gt(x)==gt(y))?y:x);}if(!g) root=x;
}//Put the x under the g
void find(int x){if(!root) return;int u=root;while(ch[u][x>v[u]]&&x^v[u]) u=ch[u][x>v[u]];splay(u);
}//Find the closest node and put it under the root
void insert(int x){int u=root,fu=0;while(u&&v[u]!=x){fu=u,u=ch[u][x>v[u]];}if(u) ++cnt[u];else{u=++tot;if(fu) ch[fu][x>v[fu]]=u;fa[u]=fu;v[u]=x;cnt[u]=siz[u]=1;}splay(u);
}//Insert the x
//1.Find the root which should be inserted
//2.If there is a node as same as it,plus its cnt
//3.Else plus a node
//4.Make the new node be the root
int nxt(int x,int f){find(x);int u=root;if(v[u]>x&&f) return u;if(v[u]<x&&!f) return u;u=ch[u][f];while(ch[u][!f]) u=ch[u][!f];return u;
}//Find the suc or the pre of the x
//After finding x,then
//The pre is the biggest one in left tree
//The suc is the smallest one in right tree
void dele(int x){int lt=nxt(x,0),nt=nxt(x,1);splay(lt);splay(nt,lt);int tx=ch[nt][0];if(cnt[tx]>1) --cnt[tx],splay(tx);else ch[nt][0]=0;
}//Find the pre and the suc of the x
//Splay(pre),splay(suc,pre)
//Then delete the left son of the suc
int kth(int k){int u=root,sn=0;for(;;){sn=ch[u][0];if(k>siz[sn]+cnt[u]) k-=siz[sn]+cnt[u],u=ch[u][1];else if(siz[sn]>=k) u=sn;else return v[u];}
}
int main()
{insert(2147483647);insert(-2147483647);scanf("%d",&t);while(t--){int op,x;scanf("%d%d",&op,&x);if(op==1) insert(x);else if(op==2) dele(x);else if(op==3) find(x),printf("%d\n",siz[ch[root][0]]);else if(op==4) printf("%d\n",kth(x+1));else if(op==5) printf("%d\n",v[nxt(x,0)]);else printf("%d\n",v[nxt(x,1)]);}return 0;
}

相关文章:

Splay

前言 Splay是一种维护平衡二叉树的算法。虽然它常数大&#xff0c;而且比较难打&#xff0c;但Splay十分方便&#xff0c;而且LCT需要用到。 约定 cnticnt_icnti​&#xff1a;节点iii的个数 valival_ivali​&#xff1a;节点iii的权值 sizisiz_isizi​&#xff1a;节点iii的子…...

智能网联汽车ASIL安全等级如何划分

目录一、功能安全标准二、功能安全等级定义三、危险事件的确定四、ASIL安全等级五、危险分析和风险评定六、功能安全目标的分解一、功能安全标准 ISO 26262《道路车辆功能安全》脱胎于IEC 61508《电气/电子/可编程电子安全系统的功能安全》&#xff0c;主要定位在汽车行业&…...

Stable Diffusion 1 - 初始跑通 文字生成图片

文章目录关于 Stable DiffusionLexica代码实现安装依赖库登陆 huggingface查看 huggingface token下载模型计算生成设置宽高测试迭代次数生成多列图片关于 Stable Diffusion A latent text-to-image diffusion model Stable Diffusion 是一个文本到图像的潜在扩散模型&#xff…...

【cuda入门系列】通过代码真实打印线程ID

【cuda入门系列】通过代码真实打印线程ID1.gridDim(6,1),blockDim(4,1)2.gridDim(3,2),blockDim(2,2)【cuda入门系列之参加CUDA线上训练营】在Jetson nano本地跑 hello cuda&#xff01; 【cuda入门系列之参加CUDA线上训练营】一文认识cuda基本概念 【cuda入门系列之参加CUDA线…...

【Python语言基础】——Python NumPy 数据类型

Python语言基础——Python NumPy 数据类型 文章目录 Python语言基础——Python NumPy 数据类型一、Python NumPy 数据类型一、Python NumPy 数据类型 Python 中的数据类型 默认情况下,Python 拥有以下数据类型: strings - 用于表示文本数据,文本用引号引起来。例如 “ABCD”…...

数据工程师需要具备哪些技能?

成为数据工程师需要具备哪些技能&#xff1f;数据工程工作存在于各个行业&#xff0c;在银行业、医疗保健业、大型科技企业、初创企业和其他行业找到工作机会。许多职位描述要求数据工程师、拥有数学或工程学位&#xff0c;但如果有合适的经验学位往往没那么重要。 大数据开发…...

Cosmos 基础 -- Ignite CLI(二)Module basics: Blog

一、快速入门 Ignite CLI version: v0.26.1 在本教程中&#xff0c;我们将使用一个模块创建一个区块链&#xff0c;该模块允许我们从区块链中写入和读取数据。这个模块将实现创建和阅读博客文章的功能&#xff0c;类似于博客应用程序。最终用户将能够提交新的博客文章&#x…...

Quartz 快速入门案例,看这一篇就够了

前言 Quartz 是基于 Java 实现的任务调度框架&#xff0c;对任务的创建、修改、删除、触发以及监控这些操作直接提供了 api&#xff0c;这意味着开发人员拥有最大的操作权&#xff0c;也带来了更高的灵活性。 什么是任务调度&#xff1f; 任务调度指在将来某个特定的时间、固…...

图解LeetCode——1233. 删除子文件夹(难道:中等)

一、题目 你是一位系统管理员&#xff0c;手里有一份文件夹列表 folder&#xff0c;你的任务是要删除该列表中的所有 子文件夹&#xff0c;并以 任意顺序 返回剩下的文件夹。 如果文件夹 folder[i] 位于另一个文件夹 folder[j] 下&#xff0c;那么 folder[i] 就是 folder[j] …...

Doris--简单使用

一、数据表的创建与数据导入 1.1、创建表 1.1.1、单分区 CREATE TABLE table1 (siteid INT DEFAULT 10,citycode SMALLINT,username VARCHAR(32) DEFAULT ,pv BIGINT SUM DEFAULT 0 -- 聚合模型&#xff0c; value column 使用sum聚合 ) AGGREGATE KEY(siteid, citycode, …...

使用GPT让你的RStudio如虎添翼

API的的调用目前来说不限制地区&#xff0c;但是OpenAI的API的申请限制了地区。运行的时候&#xff0c;如果出现了429&#xff0c;意味着你被限流了&#xff0c;需要等一会才行。 前提是&#xff0c;你需要注册一个OpenAI的账户&#xff0c;然后在https://openai.com/api/ 里申…...

Python 算法交易实验45 再探量化

说明 去年大部分精力都在构建底层架构和工具了,一直都没有时间搞量化。目前底层的数据库服务(ADB)和清洗(衍生 AETL) 工具已经好了,我想尽快的把量化启动起来。 内容 1 思想 作为交易来说,只有买卖。通过数据分析与模型,我们获得的增强点是决策。在合适的时候进行买卖的…...

Dubbo加载配置文件方式,加载流程,加载配置文件源码解析

配置方法 API配置 以Java编码的方式组织配置&#xff0c;Dubbo3配置API详解 &#xff1a;https://dubbo.apache.org/zh/docs3-v2/java-sdk/reference-manual/config/api/#bootstrap-api public static void main(String[] args) throws IOException {ServiceConfig<Greet…...

十大开源测试工具和框架,一定有你需要的

目录 前言 Katalon Studio Selenium Appium JMeter SOAP UI Robot Framework Watir JUnit Robotium Citrus 总结 前言 免费的开源框架和工具由于其开源特性&#xff0c;现在逐渐成为自动化测试的首选解决方案。区别在于&#xff0c;你是喜欢使用类库编写一个全新的…...

加密技术在android中的应用

1、算法基础 算法基础参照linux的全盘加密与文件系统加密在android中的应用 消息摘要算法 对称加密算法 非对称加密算法...

备战蓝桥杯【一维前缀和】

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…...

研报精选230214

目录 【行业230214艾瑞股份】中国增强现实&#xff08;AR&#xff09;行业研究报告【行业230214国信证券】信息安全深度剖析5&#xff1a;密评和信创双催化&#xff0c;密码产业开启从1到N【行业230214民生证券】磁性元器件深度报告&#xff1a;乘新能源之风&#xff0c;磁性元…...

【SSL/TLS】准备工作:证书格式

证书格式1. 格式说明1.1 文件编码格式1.2 文件后缀格式2. xca导出格式1. 格式说明 1.1 文件编码格式 1. PEM格式: 使用Base 64 ASCII进行编码的纯文本格式。后缀为“.pem”, ".cer", ".crt", ".key" 2. DER格式 二进制编码格式&#xff0c;文件…...

Linux常用命令---系统常用命令

Linux系统常用命令场景一&#xff1a; 查看当前系统内核版本相关信息场景二&#xff1a; sosreport 命令场景三&#xff1a; 如何定位并确定命令&#xff1f;场景四&#xff1a;查看当前系统运行负载怎场景五&#xff1a; 查看当前系统的内存可用情况场景六&#xff1a;查看网卡…...

C 结构体

C 数组允许定义可存储相同类型数据项的变量&#xff0c;结构是 C 编程中另一种用户自定义的可用的数据类型&#xff0c;它允许您存储不同类型的数据项。结构用于表示一条记录&#xff0c;假设您想要跟踪图书馆中书本的动态&#xff0c;您可能需要跟踪每本书的下列属性&#xff…...

眼图原理与信号完整性分析技术详解

眼图原理与信号完整性分析技术 1. 眼图基础概念 1.1 眼图定义与形成机制 眼图是通过示波器余辉作用将扫描所得的每个码元波形重叠形成的图形。当使用示波器跨接在接收滤波器输出端&#xff0c;并调整扫描周期与接收码元周期同步时&#xff0c;屏幕上显示的图形因其形似人眼而…...

告别Anaconda臃肿安装!用VSCode+Miniconda打造轻量级Python数据分析环境

轻量级Python数据分析环境&#xff1a;VSCodeMiniconda高效组合方案 为什么需要告别Anaconda&#xff1f; 在数据科学领域&#xff0c;开发环境的效率直接影响工作产出。传统Anaconda发行版虽然功能全面&#xff0c;但其庞大的体积&#xff08;通常超过3GB&#xff09;和缓慢…...

CentOS 7下Google Chrome离线安装全攻略(附依赖包下载清单)

CentOS 7下Google Chrome离线安装全攻略&#xff08;附依赖包下载清单&#xff09; 在企业级Linux环境中&#xff0c;CentOS 7因其稳定性和安全性仍然是许多组织的首选。然而&#xff0c;当需要在隔离网络环境下部署现代浏览器时&#xff0c;依赖关系往往成为技术人员的噩梦。…...

SDMatte透明物体模式深度解析:为什么玻璃杯开启后边缘断裂明显减少?

SDMatte透明物体模式深度解析&#xff1a;为什么玻璃杯开启后边缘断裂明显减少&#xff1f; 1. 透明物体抠图的挑战 透明物体抠图一直是图像处理领域的难题。当我们尝试用传统方法抠取玻璃杯、薄纱这类半透明物体时&#xff0c;经常会遇到以下问题&#xff1a; 边缘断裂&…...

计算机毕业设计springboot社区物业管理系统 基于SpringBoot的智慧社区综合服务平台 基于SpringBoot的小区数字化运营管理系统

计算机毕业设计springboot社区物业管理系统59b07osb &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。 在快速城市化的今天&#xff0c;社区物业管理作为城市生活的重要组成部分&a…...

别再让漏洞扫描报警了!手把手教你给老旧Linux服务器升级OpenSSH和OpenSSL(附systemd服务修复秘籍)

企业级Linux服务器安全加固实战&#xff1a;OpenSSH与OpenSSL深度升级指南 凌晨三点&#xff0c;刺耳的安全告警声再次划破运维中心的宁静——漏洞扫描报告上醒目的红色标记显示&#xff1a;OpenSSH 7.4存在CVE-2023-38408高危漏洞。这不是演习&#xff0c;而是每位运维工程师都…...

风力发电变桨系统避坑指南:从编码器选型到限位开关安装的5个关键细节

风力发电变桨系统避坑指南&#xff1a;从编码器选型到限位开关安装的5个关键细节 在风电行业摸爬滚打多年的工程师们都清楚&#xff0c;变桨系统就像风力发电机组的"神经系统"&#xff0c;任何一个环节的微小失误都可能导致整个系统瘫痪。不同于实验室环境&#xff0…...

ai辅助开发对比:github copilot与快马多模型在学生项目中的表现

最近在折腾学生项目时&#xff0c;发现AI编程助手的选择越来越多。作为通过GitHub学生认证的开发者&#xff0c;原本一直用Copilot当主力工具&#xff0c;但偶然接触到InsCode(快马)平台的多模型支持后&#xff0c;突然想做个系统性对比。于是花了周末时间搭建了个AI辅助开发评…...

TwiBot-22全流程实战指南:Twitter机器人检测与图结构识别

TwiBot-22全流程实战指南&#xff1a;Twitter机器人检测与图结构识别 【免费下载链接】TwiBot-22 项目地址: https://gitcode.com/gh_mirrors/tw/TwiBot-22 TwiBot-22是目前最全面的Twitter机器人检测基准项目&#xff0c;通过图结构分析技术识别社交网络中的机器人账号…...

从RRT到平滑轨迹:机械臂避障规划仿真全流程解析

1. 机械臂避障规划的核心挑战 机械臂在复杂环境中执行任务时&#xff0c;如何安全高效地避开障碍物是工业自动化领域的经典难题。想象一下&#xff0c;当一台六轴机械臂需要在布满设备的车间里抓取零件时&#xff0c;它的运动路径就像在迷宫中寻找出口——不仅要到达目的地&…...