luogu P3369 【模板】普通平衡树
————————————————
版权声明:本文为CSDN博主「ModestCoder_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ModestCoder_/article/details/90139481
清空一个节点
确定一个节点是父亲的左儿子还是右儿子
更新一个节点
把一个点连到另一点下面
上旋
splay
插入一个点
查询一个数的排名
查询排名为k的数
前驱、后继
删除一个点
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
int sz, rt, f[maxn], key[maxn], size[maxn], recy[maxn], son[maxn][]; inline int read(){
int s = , w = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -;
for (; isdigit(c); c = getchar()) s = (s << ) + (s << ) + (c ^ );
return s * w;
} void clear(int x){
f[x] = key[x] = size[x] = recy[x] = son[x][] = son[x][] = ;
//5个数组全部清零
} int get(int x){
return son[f[x]][] == x;
//如果自己是父亲的右儿子,返回1;否则返回0(0为左儿子,1为右儿子)
} void update(int x){
if (x){//如果这个点存在
size[x] = recy[x];//自己重复的次数先累计
if (son[x][]) size[x] += size[son[x][]];
if (son[x][]) size[x] += size[son[x][]];
//如果存在儿子,把儿子的size累积到自己
//然后发现一个问题,更新自己的size时,必须保证儿子的size是正确的
//所以后面的操作,当牵扯到儿子和父亲时,应该先更新新儿子,后更新新父亲
}
} void connect(int x, int y, int z){//x连到y下面,关系为z
if (x) f[x] = y;//存在x,则x的父亲为y
if (y) son[y][z] = x;//存在y,y的z关系儿子为x
} void rotate(int x){//上旋x
int fa = f[x], ffa = f[fa], m = get(x), n = get(fa);//确定x,fa的关系
connect(son[x][m ^ ], fa, m);//把要转的儿子转到父亲下,关系为m
connect(fa, x, m ^ );//把父亲转到自己下面,关系为m^1
connect(x, ffa, n);//把自己转到父亲的父亲下,关系为n
update(fa), update(x);//先更新fa,再更新自己,可以自己想想为什么是这个顺序
} void splay(int x){
for (int fa; fa = f[x]; rotate(x))//每次总是旋转自己
if (f[fa]) rotate(get(x) == get(fa) ? fa : x);//如果有爷爷(父亲的父亲),看父亲与父亲的父亲的关系决定转哪个
rt = x;//别忘了,把根赋为当前点
} void insert(int x){
if (!rt){//树中没有一个节点
rt = ++sz;
key[rt] = x;
size[rt] = recy[rt] = ;
son[rt][] = son[rt][] = ;//赋初值
return;
}
int now = rt, fa = ;
while (){
if (key[now] == x){//树中已有此点,重复+1
++recy[now];
update(now); update(fa);
splay(now);//splay一下,保证平衡
return;
}
fa = now, now = son[now][x > key[now]];//满足二叉查找树的性质,往下跑
if (!now){
++sz;
key[sz] = x;
size[sz] = recy[sz] = ;//赋初值
f[sz] = fa;//父亲是fa
son[fa][x > key[fa]] = sz;//更新父亲的新儿子
update(fa);//更新父亲的size
splay(sz);//splay一下,保证平衡
return;
}
}
} int find(int x){//查排名
int now = rt, ans = ;
while (){
if (x < key[now]){
now = son[now][]; continue;//在左子树中
}
ans += size[son[now][]];//排名加上左子树节点个数
if (x == key[now]){ splay(now); return ans + ; }//值等于当前点,splay一下,保证平衡,排名+1为当前排名
ans += recy[now];//排名加上当前节点的数的个数
now = son[now][];//在右子树中
}
} int kth(int x){//查找排名为x的数
int now = rt;
while (){
if (son[now][] && x <= size[son[now][]]){//在左子树中
now = son[now][]; continue;
}
if (son[now][]) x -= size[son[now][]];//存在左儿子,排名减去左子树节点数
if (x <= recy[now]){ splay(now); return key[now]; }//说明就是当前点,splay一下,保证平衡,退出
x -= recy[now];//排名减去当前节点数的个数
now = son[now][];//在右子树中
}
} int pre(){//前驱为左子树中最大的那个
int now = son[rt][];
while (son[now][]) now = son[now][];
return now;
} int nxt(){//后继为右子树中最小的那个
int now = son[rt][];
while (son[now][]) now = son[now][];
return now;
} void del(int x){
int no_use = find(x);//find主要是把当前数的对应点找到,然后旋到根,返回值的排名在这里没用
if (recy[rt] > ){//情况1:有重复,重复-1,更新,退出
--recy[rt];
update(rt);
return;
}
//接下来都是没有重复的情况
if (!son[rt][] && !son[rt][]){//情况2:没有儿子,直接清空
clear(rt);
rt = ;
return;
}
if (!son[rt][]){//情况3:没有左儿子,只有右儿子,右儿子变成根,清除自己
int tmp = rt;
f[rt = son[rt][]] = ;
clear(tmp);
return;
}
if (!son[rt][]){//情况4:没有右儿子,只有左儿子,左儿子变成根,清除自己
int tmp = rt;
f[rt = son[rt][]] = ;
clear(tmp);
return;
}
//情况5:两个儿子都有,这是需要一个很简便的做法
//把前驱splay到根,保持左子树其他节点不用动
//原根右儿子变成前驱的右儿子
//原根功成身退,清除掉
//最后对前驱的size进行更新
int tmp = rt, left = pre();
splay(left);
connect(son[tmp][], rt, );
clear(tmp);
update(rt);
} int main(){
int M = read();
while (M--){
int opt = read(), x = read();
if (opt == ) insert(x);
if (opt == ) del(x);
if (opt == ) printf("%d\n", find(x));
if (opt == ) printf("%d\n", kth(x));
if (opt == ){
insert(x); printf("%d\n", key[pre()]); del(x);
}
if (opt == ){
insert(x); printf("%d\n", key[nxt()]); del(x);
}
}
return ;
}
luogu P3369 【模板】普通平衡树的更多相关文章
- [luogu P3369]【模板】普通平衡树(Treap/SBT)
[luogu P3369][模板]普通平衡树(Treap/SBT) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除x数(若有多个相同的数,因只删 ...
- 数组splay ------ luogu P3369 【模板】普通平衡树(Treap/SBT)
二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) #include <cstdio> #define Max 100005 #define Inline _ ...
- 替罪羊树 ------ luogu P3369 【模板】普通平衡树(Treap/SBT)
二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) 闲的没事,把各种平衡树都写写 比较比较... 下面是替罪羊树 #include <cstdio> #inc ...
- 红黑树 ------ luogu P3369 【模板】普通平衡树(Treap/SBT)
二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) 近几天闲来无事...就把各种平衡树都写了一下... 下面是红黑树(Red Black Tree) 喜闻乐见拿到了luo ...
- luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)
luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- Luogu P2742 模板-二维凸包
Luogu P2742 模板-二维凸包 之前写的实在是太蠢了.于是重新写了一个. 用 \(Graham\) 算法求凸包. 注意两个向量 \(a\times b>0\) 的意义是 \(b\) 在 ...
- luoguP3391[模板]文艺平衡树(Splay) 题解
链接一下题目:luoguP3391[模板]文艺平衡树(Splay) 平衡树解析 这里的Splay维护的显然不再是权值排序 现在按照的是序列中的编号排序(不过在这道题目里面就是权值诶...) 那么,继续 ...
- luoguP3369[模板]普通平衡树(Treap/SBT) 题解
链接一下题目:luoguP3369[模板]普通平衡树(Treap/SBT) 平衡树解析 #include<iostream> #include<cstdlib> #includ ...
- 【luogu P3369 普通平衡树(Treap/SBT)】 模板 Splay
题目链接:https://www.luogu.org/problemnew/show/P3369 #include <cstdio> #include <algorithm> ...
随机推荐
- qt creator源码全方面分析(0)
本人主攻C++和Qt. 上两天刚研究完Qt install framework(IFW)应用程序安装框架. google没发现有正儿八经的官方文档的翻译,我就进行了翻译哈!! 系列文章具体见:http ...
- Linux下启动/关闭Oracle
一.Linux下启动Oracle Linux下启动Oracle分为两步: 1)启动监听: 2)启动数据库实例: 1.登录服务器,切换到oracle用户,或者以oracle用户登录 [admin@dat ...
- CUDA学习(四)之使用全局内存进行归约求和(一个包含N个线程的线程块)
问题:使用CUDA进行数组元素归约求和,归约求和的思想是每次循环取半. 详细过程如下: 假设有一个包含8个元素的数组,索引下标从0到7,现通过3次循环相加得到这8个元素的和,使用一个间隔变量,该间隔变 ...
- Django部署--uwsgi配置--nginx服务器配置
uwsgi.ini文件 [uwsgi] #使用nginx连接时使用,Django程序所在服务器地址 socket=127.0.0.1:8000 #直接做web服务器使用,Django程序所在服务器地址 ...
- HTML简介介绍
网页概述 网页:纯文本格式的文件:(以村文本格式编写,后缀名改为HTML的文本文件) ---- 网站:多个网页的集合: ---- 主页:打开网站后显示的第一个页面: ---- 浏览器:将纯文本格式的文 ...
- Unreal Engine 4 蓝图完全学习教程(五)—— 关于数组
Ⅰ.数组的含义及使用 数组是能统一保存若干数值的特殊变量.数组可以指定编号.运用其中的值,因此能够有序地管理大量的数据. 首先试图将上次创建的msg变量修改成数组,在细节栏点击修改: 并选择“修改变量 ...
- 14、 NAT
私有IP地址段:10.0.0.0-10.255.255.255/8172.16.0.0-172.31.255.255/12192.168.0.0-192.168.255.255/16 NAT的必要性: ...
- 10、VLAN
VLAN综述:1.分段2.灵活性3.安全性 一个VLAN=一个广播域=逻辑网段(子网) VLAN运作:1.每个逻辑的VLAN就象一个独立的物理桥2.交换机上的每一个端口都可以分配给不同的VLAN3.默 ...
- An internal error occurred during: "Launching New_configuration". Path for project must have only on
在Eclipse中按照如下操作 Project -> Properties -> Run/Debug Settings: 1. select "Launching New_con ...
- js 浏览器兼容问题及解决办法
JS中出现的兼容性问题的总结 1.关于获取行外样式 currentStyle 和 getComputedStyle 出现的兼容性问题 我们都知道js通过style不可以获取行外样式,当我们需要获取行 ...