普通平衡树

题意:略,题中较清晰。

用二叉查找树来存储数据,为了增加效率,尽量使左子树和右子树的深度差不超过一,这样可以时间控制在logn,效率比较高。

右旋和左旋,目的是为了维护二叉树的操作,使其尽量平衡。

int n, m;
int o[N];
struct Node { // 节点int l, r; // 左儿子,右儿子int key, val; // 数据值,随机值(用以维护二叉树尽量平衡的条件) int cnt, size; // 当前key值的数量,当前子树的所有节点的cnt值和
} tr[N];
int root, idx; // 根节点,下一个可以分配的节点序号void push_up(int p) { // 与线段树操作的意义一样tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + tr[p].cnt; // 左右子树的size和加上本身cnt
}int get_node(int key) { // 创建一个节点,返回节点序号tr[++ idx].key = key; // 初始化keytr[idx].val = rand(); // 随机一个01给valtr[idx].cnt = tr[idx].size = 1; // 数量为1,只有本身return idx; // 返回序号
}void build() { // 建立一个空的二叉树,只有两个哨兵,无穷大与无穷小get_node(-INF), get_node(INF);root = 1, tr[1].r = 2; push_up(root);
}void zig(int &p) { // 右旋int q = tr[p].l; // q为根节点左儿子tr[p].l = tr[q].r, tr[q].r = p, p = q; // 对应图片分析push_up(tr[p].r), push_up(p); // 更新size值
}void zag(int &p) { // 左旋int q = tr[p].r; // q为根节点右儿子tr[p].r = tr[q].l, tr[q].l = p, p = q; // 对应图片分析push_up(tr[p].l), push_up(p); // 更新size值
}void insert(int &p, int key) { // 插入一个节点keyif(!p) p = get_node(key); // 该key值未出现过,创建一个新的节点,并将序号返回到上一级else if(tr[p].key == key) tr[p].cnt ++; // 出现过,直接cnt数量加一else if(tr[p].key > key) { // 应该插在左儿子insert(tr[p].l, key); // 递归左儿子if(tr[tr[p].l].val > tr[p].val) zig(p); // 左儿子val值大于本身,右旋处理} else { // 应该插在右儿子insert(tr[p].r, key); // 递归右儿子if(tr[tr[p].r].val > tr[p].val) zag(p); // 右儿子var值大于本身,左旋处理}push_up(p); // 更新size状态return ;
}void remove(int &p, int key) { // 删除一个key值节点if(!p) return ; // 没找到,直接结束if(tr[p].key == key) { // 找到key值节点if(tr[p].cnt > 1) tr[p].cnt --; // 数量不唯一,直接减一即可else if(tr[p].l || tr[p].r) { // 数量唯一且存在儿子if(!tr[p].r || tr[tr[p].l].val > tr[tr[p].r].val) {// 右儿子存在或者左儿子var值大于右儿子,右旋处理zig(p);remove(tr[p].r, key);// 右旋之后key值节点交换到当前p节点的右儿子,遍历右儿子,一直递归直到没有儿子的时候删除} else {// 应该进行左旋处理zag(p);remove(tr[p].l, key);// 左旋之后key值节点交换到当前p节点的左儿子,遍历左儿子,一直递归直到没有儿子的时候删除}} else p = 0; // 数量唯一且没有儿子,直接删除即可。} else if(tr[p].key > key) remove(tr[p].l, key); // key值点在左儿子else remove(tr[p].r, key); // key值点在右儿子push_up(p);
}int get_rank_by_key(int p, int key) { // 根据key值找排名if(!p) return 1;  // 没找到直接return 1,因为洛谷这个题说的是不存在的数的排名为比它的数量加一if(tr[p].key == key) return tr[tr[p].l].size + 1; // 找到key值,返回key值在当前子树的排名if(tr[p].key > key) return get_rank_by_key(tr[p].l, key);// key在左子树return get_rank_by_key(tr[p].r, key) + tr[tr[p].l].size + tr[p].cnt; // key在右子树,因为左子树以及本身都是比它小的,所以需要加上这些数量,再去递归右子树,计算key值在右子树的排名
}
int get_key_by_rank(int p, int rank) {  // 找到排名为rank的key值if(!p) return INF; // 没找到,不存在这个排名的数if(tr[tr[p].l].size >= rank) return get_key_by_rank(tr[p].l, rank); // 在左子树if(tr[tr[p].l].size + tr[p].cnt >= rank) return tr[p].key; // 在本身return get_key_by_rank(tr[p].r, rank - tr[tr[p].l].size - tr[p].cnt); // 在右子树,需要减去左子树以及本身的数量	
}
int get_prev(int p, int key) { // 获得比key小的最大数if(!p) return -INF; // 没找到if(tr[p].key >= key) return get_prev(tr[p].l, key); // 在左子树return max(tr[p].key, get_prev(tr[p].r, key)); // 本身和右子树都比key小,都有可能,递归右子树与本身进行判断。
}
int get_next(int p, int key) { // 获得比key大的最小数if(!p) return INF; // 没找到if(tr[p].key <= key) return get_next(tr[p].r, key); // 在右子树return min(tr[p].key, get_next(tr[p].l, key));  // 本身和左子树都比key大,都有可能,递归左子树与本身进行判断。
}
inline void sovle() {build();
//	cout << idx << endl;cin >> n;while(n --) {int opt, x;cin >> opt >> x;if(opt == 1) insert(root, x);else if(opt == 2) remove(root, x);else if(opt == 3) cout << get_rank_by_key(root, x) - 1 << endl;else if(opt == 4) cout << get_key_by_rank(root, x + 1) << endl;else if(opt == 5) cout << get_prev(root, x) << endl;else cout << get_next(root, x) << endl;}
}

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

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

相关文章

【计算思维】蓝桥杯STEMA 科技素养考试真题及解析 6

1、明明买了一个扫地机器人&#xff0c;可以通过以下指令控制机器人运动: F:向前走 10 个单位长度 L:原地左转 90 度 R:原地右转 90 度 机器人初始方向向右&#xff0c;需要按顺序执行以下那条指令&#xff0c;才能打扫完下图中的道路 A、F-L-F-R-F-F-R-F-L-F B、F-R-F-L-F-F…

innoDB的缓冲池(Buffer Pool)的工作原理

数据存在磁盘了&#xff0c;总不能次次和磁盘交互吧&#xff0c;所以innoDB有一个缓冲池&#xff08;Buffer Pool&#xff09;&#xff0c;有了缓冲池后&#xff0c;读写就优先在缓冲池了。读先在缓冲池读&#xff0c;没有再去磁盘加载进缓冲池&#xff1b;写也是先写缓冲池&am…

CSGO搬砖干货,全网最详细教学!

CSGO游戏搬砖全套操作流程及注意事项&#xff08;第一课&#xff09; 在电竞游戏中&#xff0c;CSGO&#xff08;Counter-Strike: Global Offensive&#xff09;被广大玩家誉为经典之作。然而&#xff0c;除了在游戏中展现个人实力和团队合作外&#xff0c;有些玩家还将CSGO作为…

git 更换远程仓库地址三种方法总结分享

因为公司更改了 gitlab 的网段地址&#xff0c;发现全部项目都需要重新更改远程仓库的地址了&#xff0c;所以做了个记录&#xff0c;说不定以后还会用到呢。 一、不删除远程仓库修改&#xff08;最方便&#xff09; # 查看远端地址 git remote -v # 查看远端仓库名 git rem…

Java开源ETL工具-Kettle

一、背景 公司有个基于Kettle二次开发产品主要定位是做一些数据ETL的工作, 所谓的ETL就是针对数据进行抽取、转换以及加载的过程&#xff0c;说白了就是怎么对原始数据进行清洗&#xff0c;最后拿到我们需要的、符合规范的、有价值的数据进行存储或者分析的过程。 一般处理ETL的…

Ubuntu18 Opencv3.4.12 viz 3D显示安装、编译、使用、移植

Opencv3.*主模块默认包括两个3D库 calib3d用于相机校准和三维重建 &#xff0c;viz用于三维图像显示&#xff0c;其中viz是cmake选配。 参考&#xff1a; https://docs.opencv.org/3.4.12/index.html 下载linux版本的源码 sources。 查看cmake apt list --installed | grep…

代码随想录算法训练营Day 60 || 84.柱状图中最大的矩形

84.柱状图中最大的矩形 力扣题目链接(opens new window) 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 1 < heights.length <10^50 < hei…

数据库实验三 Sql多表查询和视图

数据库实验三 Sql多表查询和视图 一、Sql表二、在线练习 一、Sql表 www.db-book.com 二、在线练习 对所有表执行查询语句&#xff0c;查看有哪些数据。 select * from tableName; 一、执行以下查询语句&#xff0c;写出查询意图。 (1) select * from student,takes whe…

YOLOv7独家改进: Inner-IoU基于辅助边框的IoU损失,高效结合 GIoU, DIoU, CIoU,SIoU 等 | 2023.11

💡💡💡本文独家改进:Inner-IoU引入尺度因子 ratio 控制辅助边框的尺度大小用于计算损失,并与现有的基于 IoU ( GIoU, DIoU, CIoU,SIoU )损失进行有效结合 推荐指数:5颗星 新颖指数:5颗星 收录: YOLOv7高阶自研专栏介绍: http://t.csdnimg.cn/tYI0c …

Redis -- 介绍

1、NoSQL: 指的是非关系型数据库&#xff0c;主要分成四大类&#xff1a;键值存储数据库、列存储数据库、文档型数据库、图形数据库。 2、什么是Redis&#xff1a; Redis是一种基于内存的数据库&#xff0c;一般用于做缓存的中间件。 3、Redis的主要的特点&#xff1a; 1、Rd…

投标文件如何写【格式层面】

一、顶级标题的修改&#xff08;1级标题的修改&#xff09; 修改的内容&#xff0c;核心是样式多级序号&#xff1b; 样式解决&#xff1b;标题1&#xff0c;标题2&#xff0c;解决快速排版的问题 多级标号解决如1.1,1.2.1,1.3.4等类似的自动编号的规划设置&#xff0c;如果…

Oracle-客户端连接报错ORA-12545问题

问题背景: 用户在客户端服务器通过sqlplus通过scan ip登陆访问数据库时&#xff0c;偶尔会出现连接报错ORA-12545: Connect failed because target host or object does not exist的情况。 问题分析&#xff1a; 首先&#xff0c;登陆到连接有问题的客户端数据库上&#xff0c;…