题意

写一棵平衡树,需要实现如下几种操作:

  1. 插入 xxx 数
  2. 删除 xxx 数(若有多个相同的数,因只删除一个)
  3. 查询 xxx 数的排名(排名定义为比当前数小的数的个数 +1+1+1 )
  4. 查询排名为 xxx 的数
  5. 求 xxx 的前驱(前驱定义为小于 xxx,且最大的数)
  6. 求 xxx 的后继(后继定义为大于 xxx,且最小的数)

思路

BST

什么是BST(二叉查找树)呢?

BST是一种二叉树,用于做一些查找操作(其实很多是题意中所说明的工作)。BST需要满足当前结点的左子树中所有结点的键值要小于当前结点,而右子树相反,所有结点的键值都要大于当前节点。

BST的性质:

  • 一棵BST能对应一个键的集合
  • 一个集合对应的BST不为一
  • 对BST做中序遍历,得到的序列是严格单调递增的

Treap

Treap是一种编程比较简单的平衡树,它在普通二叉搜索树的基础上,给每个结点一个随机的优先级。树上每个结点在满足BST的性质以外,还需要根据优先级满足堆的性质。

旋转操作

为了要让Treap同时满足BST和堆的性质,肯定要对其结构进行调整。这个调整的方式被称为旋转。在Treap中,只有两种旋转操作——左旋和右旋

左旋一个子树,会把它的根挪到根的左子树部分,同时根的右子树成为子树的根,再把右子树的左子树接到根的右子树上。

右旋一个子树,会把它的根转到右子树上,同时根的左子树成为子树的根。在把左子树的右子树接到根的右子树上。

插入操作

  • 如果当前没有结点,那么就到了位置,直接创建新的。
  • 如果当前结点的键值为 xxx,那么懒添加,在当前结点的出现次数记录那里直接 +1+1+1 即可。
  • 否则根据BST性质接着遍历即可。
  • 插入后如果不满足Trep的堆性质了,旋转。

删除操作

  • 如果不存在,那么返回即可。
  • 如果要删除的元素是在子树中,去子树里找
  • 如果当前要删除结点是叶子,那么直接删除。
  • 如果当前点只有一个孩子,那么直接把自己跟孩子换了就行。
  • 否则有两个孩子的话旋转一下后直接删除。

查询x数的排名

  • 如果当前节点是x,直接返回左子树大小 +1+1+1 即可。
  • 否则接着安照BST性质遍历即可。

查询排名为x的数

  • 与上一个操作很像,读者可以自行想想

前驱后继

读者也可以自行想想。

tips

我们为什么不直接用BST呢?可以想想,如果给出一个单调递增/递减的序列,是不是都一直往右子树/左子树上添加了。一个满二叉树(最好情况)的时间复杂度(层数)是 log⁡n\log{n}logn 的,但是如果都往一个方向,那么层数就变成 nnn 了,这不好。但是如果旋转,每一次都能减少一层,然后随机化也会让这个序列达到一个相对平衡的状态。所谓的堆性质也可以理解为是一个“莫须有”的罪名罢了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const ll MAXN=1e5+5;
const ll INF=2147483647;
ll root;
struct Node{ll son[2];//0为左孩子ll cnt,value,pri,size;//出现次数,值,优先级,个数
}t[MAXN];
void push_up(ll u){t[u].size=t[t[u].son[0]].size+t[t[u].son[1]].size+t[u].cnt;//为左子树的大小+右子树的大小+自身的个数
}
void rotate(ll &u,ll d){//d=0为左旋,d=1为右旋ll k=t[u].son[d^1];t[u].son[d^1]=t[k].son[d];t[k].son[d]=u;push_up(u);push_up(k);u=k;
}
ll sz;
void insert(ll &u,ll x){if(u==0){u=++sz;//新元素t[u].cnt=t[u].size=1;//叶子大小和元素个数都为1t[u].value=x;//值为xt[u].pri=rand();//随机赋优先级return;}if(t[u].value==x) {t[u].size++;//更改空间t[u].cnt++;//多了一个一样的return;}ll k=x>t[u].value;//在左子树还是右子树里insert(t[u].son[k],x);if(t[u].pri<t[t[u].son[k]].pri){//是否满足堆性质rotate(u,k^1);//旋转,旋哪个子树}push_up(u);//更新
}
void del(ll &u,ll x){if(u==0){return;//压根不存在}if(x<t[u].value){del(t[u].son[0],x);//在左子树里}else if(x>t[u].value){del(t[u].son[1],x);//在右子树里}else{if(t[u].cnt>1){t[u].size--;//懒删除t[u].cnt--;//同上}else if(t[u].son[0]==0&&t[u].son[1]==0){u=0;//叶子结点,直接删除就行了}else if(t[u].son[0]!=0&&t[u].son[1]==0){u=t[u].son[0];//接到左子树上}else if(t[u].son[0]==0&&t[u].son[1]!=0){u=t[u].son[1];//接到右子树上}else{ll k=t[t[u].son[0]].pri>t[t[u].son[1]].pri;//两边都有,选择删rotate(u,k);//旋一下,把根换到底下del(t[u].son[k],x);//接着删}}push_up(u);//更新
}
ll x_rank(ll u,ll x){if(u==0){return 0;//不存在}if(t[u].value==x){return t[t[u].son[0]].size+1;//小的元素个数再+1}if(x<t[u].value){return x_rank(t[u].son[0],x);//比当前小,在左子树里}return t[t[u].son[0]].size+t[u].cnt+ x_rank(t[u].son[1],x);//左子树的大小+当前结点元素个数+右子树中的排名
}
ll rank_x(ll u,ll x){if(t[t[u].son[0]].size>=x){return rank_x(t[u].son[0],x);//左子树的排名比x大}if(t[t[u].son[0]].size+t[u].cnt<x){return rank_x(t[u].son[1],x-t[t[u].son[0]].size-t[u].cnt);//这个结点的排名比x小,去右边,同时减掉当前排名}return t[u].value;//找到了,返回元素
}
ll pre(ll u,ll x){if(u==0){return -INF;//不存在前驱}if(t[u].value>=x){return pre(t[u].son[0],x);//比x大,去左边}return max(t[u].value, pre(t[u].son[1],x));//是不是当前的,还是在右子树里,取max
}
ll suc(ll u,ll x){if(u==0){return INF;//不存在}if(t[u].value<=x){return suc(t[u].son[1],x);//比x小,去右边}return min(t[u].value, suc(t[u].son[0],x));//选最小的,与前驱相同
}
int main(){srand(time(NULL));ll n;scanf("%lld",&n);for (int i = 1; i <=n ; ++i) {ll op,x;scanf("%lld%lld",&op,&x);if(op==1){insert(root,x);}else if(op==2){del(root,x);}else if(op==3){printf("%lld\n",x_rank(root,x));}else if(op==4){printf("%lld\n",rank_x(root,x));}else if(op==5){printf("%lld\n",pre(root,x));}else{printf("%lld\n",suc(root,x));}}return 0;
}

P3369普通平衡树相关推荐

  1. 洛谷P3369 普通平衡树

    刚学平衡树,分别用了Splay和fhq-treap交了一遍. 这是Splay的板子,貌似比较短? Splay #include <iostream> #include <cstdio ...

  2. 平衡树(splay)学习笔记(详细,从入门到精(bao)通(ling))(持续更新)

    前言 在前几天军训站军姿的时候胡思乱想,突然明白了splay的本质 KMP学习笔记后又一篇字数上万的题解- 前置技能--二叉搜索树 首先来看一个最简单的问题: 你需要维护一个数据结构,资磁这些操作: ...

  3. 快速入门Treap(代码实现)

    学习数据结构对我来说真的相当困难,网上讲\(Treap\)的我也看不太懂,前前后后花了大概六天才把\(Treap\)学会.为了避免再次忘记,这里我整理一下\(Treap\)的基础知识和模板. 阅读此文 ...

  4. fhq treap入门

    2023大厂真题提交网址(含题解): www.CodeFun2000.com(http://101.43.147.120/) 最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练 ...

  5. 浅谈 Fhq-Treap

    问题引入:Luogu P3369 普通平衡树 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入 x x x 数 删除 x x x 数(若有多个相同的数,因只删除一个) ...

  6. 【Luogu】P3369 【模板】普通平衡树(树状数组)

    P3369 [模板]普通平衡树(树状数组) 一.树状数组 树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构. ...

  7. [学习笔记] 伸展树splay详解+全套模板+例题[Luogu P3369 【模板】普通平衡树]

    文章目录 引入概念 全套模板 变量声明 update ==rotate旋转== splay操作 insert插入 delete删除 查找x的位置 查找第k大 前驱/后继 极小值-inf和极大值inf的 ...

  8. 【洛谷P3369】 (模板)普通平衡树

    https://www.luogu.org/problemnew/show/P3369 Splay模板 1 #include<iostream> 2 #include<cstdio& ...

  9. fhq treap ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

    二次联通门 : LibreOJ #104. 普通平衡树 #include <cstdio> #include <iostream> #include <algorithm ...

  10. 【洛谷P3369】普通平衡树(splay)

    emmmmm直接丢代码了 #include<iostream> #include<cstdio> #include<cstring> #include<str ...

最新文章

  1. AI一分钟 | 传许家印已投资贾跃亭FF;腾讯将发布可接收微信的智能音箱;阿里确认研发自动驾驶技术...
  2. [论文笔记] Anatomy of a crowdsourcing platform - Using the example of microworkers.com (IMIS, 2011)...
  3. Android 系统开发_四大组件篇 -- Service 解析(用法)
  4. 【译】用图表展示未知----通向报表服务的阶梯系列(五)
  5. Apache虚拟目录和多端口多主机名配置
  6. python中列表和元组的相同点和不同点_详解Python语言中元组和列表的区别
  7. JavaWeb前端:HTML5 简介
  8. java并发测试 线程池,Java并发编程——线程池
  9. 论文精读:车尧-《社会网络视角下战略性新兴产业的专利情报研究》
  10. 使用 Hibernate 二级缓存的步骤
  11. 数据采集的大致流程(离线和实时)
  12. html怎么设置用户登录界面设计,html怎么做用户登录界面设计步骤,登录界面设计这样做?...
  13. adb安装apk程序
  14. 爬虫爬取图片并保存到电脑
  15. 以Apollo为例学习/分析自动驾驶运动规划算法
  16. 重学前端第一天——HTML结构和常见的HTML元素
  17. 转载:“凤求凰”的解释,有才
  18. 学习和使用技术的4种层次
  19. java 安全包_信息加密系统设计(依托Java平台安全包)
  20. office excel无法打开超链接解决方法

热门文章

  1. ROMS模式RNT工具包的应用(弃用)
  2. 七牛云 转码_普通音视频转码(avthumb)
  3. stellarium
  4. 前端必备知识之 Nginx 复盘总结
  5. Usb ssh 管理android,Android USB VID PID 及 ADB
  6. 迅雷7 down.php,迅雷协议分析
  7. 计算机表格中减法公式,excel表格减法公式
  8. suse linux raid驱动,安装SuSE使用嵌入式SATA控制器用常见设备使用情况的megaSR swraid驱动程序...
  9. 团队项目事后诸葛亮会议
  10. html文件在线打开word,html打开word程序 html直接打开word文档