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

平衡树 - splay

相比于之前的普通平衡树进行左旋右旋来比,splay的适用性更高,使用更广泛。

核心函数rotate、splay函数,其它的根据需要进行修改。

int n, m;
struct Node {int s[2], p, v, cnt; // 左右儿子、父节点、值、出现数量int size, flag; // 子树大小、懒标记void init(int _v, int _p) { // 初始化函数v = _v, p = _p;cnt = size =  1;}
} tr[N];
int root, idx;// 根节点、分配节点序号void pushup(int u) { // 向上更新传递,与线段树一样 tr[u].size = tr[tr[u].s[0]].size + tr[tr[u].s[1]].size + tr[u].cnt;
}void pushdown(int x) { // 向下传递更新 ,与线段树一样if(tr[x].flag) {swap(tr[x].s[0], tr[x].s[1]);tr[tr[x].s[0]].flag ^= 1;tr[tr[x].s[1]].flag ^= 1;tr[x].flag = 0;}
}void rotate(int x) { // 核心函数 int y = tr[x].p, z = tr[y].p;int k = tr[y].s[1] == x;tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z;tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;tr[x].s[k ^ 1] = y, tr[y].p = x;pushup(y), pushup(x);
}void splay(int x, int k) { // 将x节点旋转到k节点下 while(tr[x].p != k) { // int y = tr[x].p; // x节点的父节点 int z = tr[y].p; // x节点的父节点的父节点 if(z != k) // 向上旋转 if((tr[y].s[1] == x) != (tr[z].s[1] == y)) rotate(x); // 转一次x else rotate(y); // 转一次y rotate(x); // 转一次x }if(!k) root = x; // 更新root节点 
}void upper(int v) { // 将v值节点转到根节点 int u = root; // 根节点 while(tr[u].s[v > tr[u].v] && tr[u].v != v) // 存在则找到v值节点,不存在则找到v值节点的前驱或者后继节点 u = tr[u].s[v > tr[u].v]; // 向下寻找 splay(u, 0); // 将u节点旋转到跟节点 
}int get_prev(int v) { // 获取v值的前驱节点 upper(v); // 将v值节点转到根节点 if(tr[root].v < v) return root; // 若是该值在树中不存在,根节点就是v的前驱或者后继节点 int u = tr[root].s[0]; // 前驱节点在左子树的最右边 while(tr[u].s[1]) u = tr[u].s[1]; // 找到最右边的一个节点 return u;
}int get_next(int v) { // 获取某值的后继节点 upper(v); // 将v值节点转到根节点if(tr[root].v > v) return root; // 若是该值在树中不存在,根节点就是v的前驱或者后继节点 int u = tr[root].s[1]; // 后继节点在右子树的最左边 while(tr[u].s[0]) u = tr[u].s[0]; // 找到最左的节点,就是最小的节点 return u; // 返回节点 
}int get_rank_by_key(int v) { // key值在当前树中的排名 upper(v); //  if(tr[root].v >= v)return tr[tr[root].s[0]].size + 1;return tr[tr[root].s[0]].size + tr[root].cnt + 1;
}int get_key_by_rank(int k) { // 获取树中排名为k的值 int u = root; // 根节点 while(tr[u].size >= k) { // 保证当前子树中有解 if(tr[tr[u].s[0]].size >= k) u = tr[u].s[0]; // 在左子树中 else if(tr[tr[u].s[0]].size + tr[u].cnt >= k) return splay(u, 0), tr[u].v; // 在当前节点 else k -= tr[tr[u].s[0]].size + tr[u].cnt, u = tr[u].s[1]; // 在右子树,需要更新k值,减去左子树以及当前节点值的数量 }return -1;
}void insert(int v) { // 在二叉树中插入一个值 int u = root, p = 0; // p维护为当前节点的父节点 while(u && tr[u].v != v) // 没找到则一直向下寻找 p = u, u = tr[u].s[v > tr[u].v]; // 更新父节点,更新当前节点 if(u) tr[u].cnt ++; // v值的节点已经存在则直接加一即可 else { // 不存在则创建节点 u = ++ idx; // 分配节点序号 if(p) tr[p].s[v > tr[p].v] = u; // 将父节点也就是前驱节点指向当前节点 tr[u].init(v, p); // 初始化当前节点的值、父节点信息 }splay(u, 0); // 将u节点旋转到根节点下
}void remove(int v) { // 删除一个值为v的节点 int prev = get_prev(v), nex = get_next(v); // 获取该节点的前驱以及后继节点。 splay(prev, 0), splay(nex, prev); // 将前继节点旋转到根节点,将后继节点旋转到前驱节点下面也就是根节点下面 int w = tr[nex].s[0]; // 后继节点的左子树就是v的节点 if(tr[w].cnt > 1) tr[w].cnt --, splay(w, 0); // 该节点的v不止存在一个,减一,w节点旋转到根节点 else tr[nex].s[0] = 0, splay(nex, 0); // 唯一,那么直接把后继节点的左子树指向空也就是0即可
}void output(int u) { // 中序遍历输出二叉树 
//	pushdown(u); int l = tr[u].s[0], r = tr[u].s[1]; // 左右儿子 if(l) output(l); // 递归左儿子 if(tr[u].v >= 1 && tr[u].v <= n) cout <<  tr[u].v << " "; // 输出当前子树的根 if(r) output(r); // 递归右儿子 
}inline void sovle() {cin >> n;insert(-INF), insert(INF); // 插入两个哨兵,无穷小以及无穷大 使得在查询某数不存在的是时候不会产生越界while(n --) {int a, b;cin >> a >> b;if(a == 1) insert(b); // 插入一个值 if(a == 2) remove(b); // 插入一个值 if(a == 3) cout << get_rank_by_key(b) - 1 << endl; // 真实排名减一 因为前面多了一个哨兵 if(a == 4) cout << get_key_by_rank(b + 1) << endl; // 真实排名加一 因为哨兵 if(a == 5) cout << tr[get_prev(b)].v << endl; if(a == 6) cout << tr[get_next(b)].v << endl;}
}

相关文章:

平衡树 - splay

相比于之前的普通平衡树进行左旋右旋来比&#xff0c;splay的适用性更高&#xff0c;使用更广泛。 核心函数rotate、splay函数&#xff0c;其它的根据需要进行修改。 int n, m; struct Node {int s[2], p, v, cnt; // 左右儿子、父节点、值、出现数量int size, flag; // 子树大…...

Spring Validation实践及其实现原理

Bean Validation 2.0 注解 校验空值 Null&#xff1a;验证对象是否为 null NotNull&#xff1a;验证对象是否不为 null NotEmpty&#xff1a;验证对象不为 null&#xff0c;且长度&#xff08;数组、集合、字符串等&#xff09;大于 0 NotBlank&#xff1a;验证字符串不为 nul…...

Java核心知识点整理大全18-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…...

vue 富文本编辑器多图上传

首先我使用的富文本编辑器是vue-quill-editor 使用npm进行下载 npm install vue-quill-editor --save当然也可以按照官方的方法下载&#xff0c;到官方 因为我是在原有老项目上开发的使用的组件库是ant-design-vue 1x版&#xff0c;当然使用其他组件库也可以 然后还有重要的一…...

简易地铁自动机售票系统实现(C++)

该程序具有以下功能 (1) 一个地铁路线类 Router&#xff0c;包含路线编号&#xff0c;途中的各个站点。可以新增、删除、查询路线&#xff0c;可以根据线路名称&#xff0c;显示线路图片。 (2) 一个地图类 Map&#xff0c;可以显示所有可以乘坐的地铁站名&#xff0c;以及线路…...

【Spark入门】基础入门

【大家好&#xff0c;我是爱干饭的猿&#xff0c;本文重点介绍Spark的定义、发展、扩展阅读&#xff1a;Spark VS Hadoop、四大特点、框架模块、运行模式、架构角色。 后续会继续分享其他重要知识点总结&#xff0c;如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff…...

【自制开源】实时调参,手写字生成神器!大学生福音,告别繁琐的手写报告。

HandwritingGenerator HandwritingGenerator 是一个使用 PyQt6 制作的手写文本图片生成器。 该工具允许用户自定义多种效果&#xff0c;通过在左边配置效果参数&#xff0c;右边实时预览&#xff0c;并在调整好后输出图片。 效果预览 软件界面预览&#xff1a;一封情书&#x…...

Python 进阶(十一):高精度计算(decimal 模块)

《Python入门核心技术》专栏总目录・点这里 文章目录 1. 导入decimal模块2. 设置精度3. 创建Decimal对象4. 基本运算5. 比较运算6. 其他常用函数7. 注意事项8. 总结 大家好&#xff0c;我是水滴~~ 在进行数值计算时&#xff0c;浮点数的精度问题可能会导致结果的不准确性。为了…...

MCU常用文件格式

1. asm文件 asm是汇编语言源程序的扩展名&#xff0c;.asm文件是以asm作为扩展名的文件&#xff0c;是汇编语言的源程序文件。汇编语言(Assembly Language)是面向机器的程序设计语言&#xff0c;是利用计算机所有硬件特性并能直接控制硬件的语言。在汇编语言中&#xff0c;用助…...

【机器学习】On the Identifiability of Nonlinear ICA: Sparsity and Beyond

前言 本文是对On the Identifiability of Nonlinear ICA: Sparsity and Beyond (NIPS 2022)中两个结构稀疏假设的总结。原文链接在Reference中。 什么是ICA(Independent component analysis)&#xff1f; 独立成分分析简单来说&#xff0c;就是给定很多的样本X&#xff0c;通…...

RBAC(Role-Based Access Control,基于角色的访问控制)

1. RBAC核心概念 RBAC&#xff08;Role-Based Access Control&#xff0c;基于角色的访问控制&#xff09;是一种广泛应用于软件和系统中的权限管理模型。它通过将用户与角色关联&#xff0c;再将角色与访问权限关联&#xff0c;来管理用户对系统资源的访问。RBAC模型的主要特…...

C++const指针的两种用法

const int *p &a; 指向const变量的指针 指向const变量的指针const修饰的变量&#xff0c;只能由指向const变量的指针去指向 p &a1;const的位置&#xff0c;必须在*的左边指向const变量的指针&#xff0c;可以被改变&#xff0c;可以指向别的变量可以指向普通变量&am…...

【Proteus仿真】【51单片机】智能垃圾桶设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器&#xff0c;使用报警模块、LCD1602液晶模块、按键模块、人体红外传感器、HCSR04超声波、有害气体传感器、SG90舵机等。 主要功能&#xff1a; 系统运行后&#xf…...

【Windows】执行tasklist/taskkill提示“错误:找不到”或者“ERROR: not found”的解决方案

原因 由于WinMgmt异常导致起不来&#xff0c;而WinMgmt是SVCHOST进程中的WMI服务&#xff0c;解决这个问题需要停止之后再重新启动。 WinMgmt是Windows 2000客户端管理的核心组件&#xff0c;当客户端应用程序连接或当管理程序需要它本身的服务时&#xff0c;这个进程就会初始…...

MS2630——Sub-1 GHz、低噪声放大器芯片

产品简述 MS2630 是一款 Sub-1 GHz 低功耗、低噪声放大器 (LNA) 芯 片。芯片采用先进制造工艺&#xff0c;采用 SOT23-6 的封装形式。 主要特点 ◼ 典型噪声系数&#xff1a; 1.57dB ◼ 典型功率增益&#xff1a; 16.3dB ◼ 典型输出 P1dB &#xff1a; -9.2dBm…...

车载以太网-数据链路层-MAC

文章目录 车载以太网MAC(Media Access Control)车载以太网MAC帧格式以太网MAC帧报文示例车载以太网MAC层测试内容车载以太网MAC(Media Access Control) 车载以太网MAC(Media Access Control)是一种用于车载通信系统的以太网硬件地址,用于在物理层上识别和管理数据包的传…...

Tomcat源码分析

Tomcat源码分析与实例 Tomcat是一个开源的Java Web服务器&#xff0c;它提供了一种简单的方式来部署和运行Java Web应用程序。本文将详细介绍Tomcat的源码分析和实例。 1. Tomcat源码分析 1.1 目录结构 Tomcat的源码目录结构如下&#xff1a; tomcat-x.y.z/ ├── bin/ ├…...

计算机视觉面试题-02

图像处理和计算机视觉基础 什么是图像滤波&#xff1f;有哪些常见的图像滤波器&#xff1f; 图像滤波是一种通过在图像上应用滤波器&#xff08;卷积核&#xff09;来改变图像外观或提取图像特征的图像处理技术。滤波器通常是一个小的矩阵&#xff0c;通过在图像上进行卷积…...

力扣日记11.27-【二叉树篇】二叉树的最大深度

力扣日记&#xff1a;【二叉树篇】二叉树的最大深度 日期&#xff1a;2023.11.27 参考&#xff1a;代码随想录、力扣 104. 二叉树的最大深度 题目描述 难度&#xff1a; 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最…...

【数据结构】树的概念以及二叉树

目录 1 树概念及结构 1.1 树的概念 1.3 树的存储 2 二叉树的概念及结构 2.1 概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储结构 1 树概念及结构 1.1 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...

Java后端检查空条件查询

通过抛出运行异常&#xff1a;throw new RuntimeException("请输入查询条件&#xff01;");BranchWarehouseServiceImpl.java // 查询试剂交易&#xff08;入库/出库&#xff09;记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...