普通平衡树

题意:略,题中较清晰。

用二叉查找树来存储数据,为了增加效率,尽量使左子树和右子树的深度差不超过一,这样可以时间控制在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; // 初始化key
	tr[idx].val = rand(); // 随机一个01给val
	tr[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) { // 插入一个节点key
	if(!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;
	}
}

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

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

相关文章

CSGO搬砖项目全面讲解 ,CSGO搬砖注意事项

Steam/CSGO游戏搬砖全套操作流程之如何选品&#xff08;第二课&#xff09; 一个游戏只要能搬&#xff0c;只要体量不够大&#xff0c;很快就会货币价格暴跌&#xff0c;直接凉凉。市面上的能稳定手动搬砖的游戏越来越少。所以对于兼职赚点外快的散人搬砖党来说&#xff0c;找一…

【Vue入门篇】基础篇—Vue指令,Vue生命周期

&#x1f38a;专栏【JavaSE】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【如愿】 &#x1f384;欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;Vue概述&#x1f384;快速入门&#x1f33a;Vue指令⭐v-…

微信小程序登录获取不到头像和昵称解决办法

微信小程序登录获取不到头像和昵称主要原因是&#xff1a;小程序wx.getUserProfile接口被收回&#xff01; 大家可以按照文档操作↓ PS&#xff1a; 针对小程序wx.getUserProfile接口将被收回后做出的授权调整 小程序文档中提出的调整说明 对于此次变化&#xff0c;现将小程…

如何满足BMW EDI项目的PKT需求?

近期宝马BMW&#xff08;以下简称BMW&#xff09;在其部分供应商之间试点推进PKT项目&#xff0c;BMW为什么要启动 PKT 计划呢&#xff1f; 业务系统全面升级统一全球所有宝马工厂的流程 宝马内部的物流供货流程 近期BMW PKT需求主要针对其内部物流供货流程展开&#xff1a; …

Android : Spinner(列表选项框) + BaseAdapter -简单应用

​​容器与适配器&#xff1a;​​​​​ http://t.csdnimg.cn/ZfAJ7 示例图&#xff1a; 实体类 Demo.java package com.example.mygridviewadapter.entity;public class Demo {private String text;private int img;public Demo(String text, int img) {this.text…

QQ怎么备份聊天记录?3个方法教你快速备份!

QQ聊天记录作为用户和亲人、好友以及同事之间沟通的凭证&#xff0c;可以帮助我们回忆起过去的交流内容。如果我们不小心误删了QQ聊天记录或者更换了新手机&#xff0c;那么这时候就需要备份聊天记录。qq怎么备份聊天记录呢&#xff1f;本文将介绍3个简单方法&#xff0c;帮助您…

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

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

va-Q-tec实现温度敏感产品运输过程质量控制温控无忧

摘要&#xff1a;温度敏感产品运输对供应链全流程的温度质量要求较高&#xff0c;往往需要借助特殊的温湿度监测技术产品。va-Q-tec与虹科Comet合作&#xff0c;采用虹科Comet的U系列温度记录仪&#xff0c;为集装箱运输过程提供完整的温控包装解决方案。 一、客户背景 va-Q-…

算法通关村第十二关-白银挑战字符串经典题目

大家好我是苏麟 , 今天带来字符串相关的题目 . 大纲 反转问题字符串反转K个一组反转仅仅反转字母反转字符串中的单词 反转问题 字符串反转 描述 : 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s的形式给出。 题目 : LeetCode 344. 反转…

【PPspliT】ppt转pdf-保留过渡动画

网址 http://www.maxonthenet.altervista.org/ppsplit.php 下载安装 使用 再次打开ppt&#xff0c;就能在上方的选项栏里头看到了&#xff1a;

【Unity】接入MAX聚合广告SDK Applovin + GoogleAdmob

版本&#xff1a; Unity&#xff1a;2019.4.35f1gradle plugin: 4.2.0 &#xff08;实际要7.0 对应build_tools:34.0.0) gradle: 6.7.1 &#xff08;实际要7.0 对应build_tools:34.0.0) jdk: 1.8.0_241build_tools: 34.0.0 ndk: android-ndk-r19 文档&#xff1a; 6.0.1(Andro…

使用宝塔安装Alist

废话不多说&#xff0c;直接上教程&#xff0c;根据我的步骤一步一步来&#xff0c;肯定可以成功&#xff01; 我这边使用一键安装的时候&#xff0c;一致报错&#xff0c;提示证书过期&#xff0c;无奈我就开始了手动安装&#xff0c;下面的教程也是手动安装的教程 首先&…

RabbitMQ安装说明

注意: 本次安装以 CentOS 7为例 1、 准备软件 erlang 18.3 1.el7.centos.x86_64.rpm socat 1.7.3.2 5.el7.lux.x86_64.rpm rabbitmq server 3.6.5 1.noarch.rpm 2、安装Erlang rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm 3.、安装RabbitMQ 安装 rpm -ivh socat-1.7.3.2-…

码云 -- 本地代码上传到码云

1. 在码云上创建远程仓库 复制远程仓库地址 2. 在本地代码上创建 git 仓库 在本地代码文件夹上&#xff0c;打开git 命令窗口 输入初始化命令&#xff0c;创建 git 仓库 git init3. 给 git 仓库添加远程仓库 继续输入 git 命令 git remote add origin 远程仓库地址4. 按 git 的…

提升性能测试效率:JMeter中的用户自定义变量!

前言 在测试过程中&#xff0c;我们经常会碰到测试服务地址有改动的情况&#xff0c;为了方便&#xff0c;我们会把访问地址参数化&#xff0c;当访问地址变化了&#xff0c;我们只需要把参数对应的值改动一下就可以了。 一&#xff1a;添加配置元件-用户定义的变量&#xff…

python命令行 引导用户填写ssh登录信息

字多不看&#xff0c;直接体验&#xff1a; 待补充 演示代码 # -*- coding:UTF-8 -*- """ author: dyy contact: douyaoyuan126.com time: 2023/11/23 9:20 file: 引导用户填写ssh接口信息.py desc: xxxxxx """# region 引入必要的依赖 impor…

腾讯云 小程序 SDK对象存储 COS使用记录,原生小程序写法。

最近做了一个项目&#xff0c;需求是上传文档&#xff0c;文档类型多种&#xff0c;图片&#xff0c;视频&#xff0c;文件&#xff0c;doc,xls,zip,txt 等等,而且文档类型可能是大文件&#xff0c;可能得上百兆&#xff0c;甚至超过1G。 腾讯云文档地址&#xff1a;https://c…

AI如何帮助IT领导者优化成本和降低风险

围绕AI的兴奋和好奇心-以及随之而来的可能性-让整个行业沸沸扬扬&#xff0c;结果不言而喻&#xff0c;32%的IT领导者表示&#xff0c;集成AI是2023年的首要任务&#xff0c;其次是降低安全风险(31%)和降低IT成本(29%)。 虽然在可预见的未来&#xff0c;AI可能是IT领导者的首要…

Navicat 技术指引 | 适用于 GaussDB 的备份与还原功能

Navicat Premium&#xff08;16.2.8 Windows版或以上&#xff09; 已支持对 GaussDB 主备版的管理和开发功能。它不仅具备轻松、便捷的可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结构同步、协同合作、数据迁移等&#xff09;&#xff0c;这…

【QML】StackView上层页面半透明,显示下层页面

1、 应用场景 有时候需要模拟弹窗效果&#xff0c;需要下层的页面半透明显示。仅仅将上层页面背景设置为透明并不能实现这个效果&#xff0c;下层的页面依然被覆盖。Qt帮助文档中有如下代码&#xff0c;经测试有效果。 2、 代码 重点标记&#xff1a; 下层页面需要设置这个…