「Splay」普通平衡树模板
口诀:
$rotate$:先上再下,最后自己
$splay$:祖父未到旋两次,三点一线旋父亲,三点折线旋自己。
$delete$:没有儿子就删光。单个儿子删自己。两个儿子找前驱。
易错点:
$rotate$:祖父不在自己做根
$delete$:自己做根父亲为0
$kth$:先减排名后转移
/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = ;
const int INF = 0x3f3f3f3f;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = ; int w = ; register char c = getchar();
for(; c ^ '-' && (c < '' || c > ''); c = getchar());
if(c == '-') w = -, c = getchar();
for(; c >= '' && c <= ''; c = getchar()) x = (x<<) + (x<<) + c - ''; return x * w;
}
int n,opt,x,num_node;
int ch[MAXN][],fa[MAXN],val[MAXN],size[MAXN],cnt[MAXN],root;
struct Splay{
inline bool rson(int f, int x){
return ch[f][] == x;
}
inline void update(int x){
size[x] = size[ch[x][]] + size[ch[x][]] + cnt[x];
}
inline void clear(int x){
val[x]=cnt[x]=size[x]=fa[x]=ch[x][]=ch[x][]=;
}
inline void rotate(int x){
int f = fa[x], gf = fa[f];
bool p = rson(f, x), q = !p;
if(gf) ch[gf][rson(gf,f)] = x; else root = x; fa[x] = gf;
ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
ch[x][q] = f, fa[f] = x;
update(f), update(x);
}
inline void splay(int x, int target){
while(fa[x] != target){
int f = fa[x], gf = fa[f];
if(gf == target){ rotate(x); break;}
if(rson(gf,f) == rson(f,x)) rotate(f); else rotate(x);
rotate(x);
}
}
inline void Insert(int v){
int o = root;
if(root == ){
root = ++num_node;
cnt[root] = size[root] = ;
val[root] = v;
return;
}
for(;o;){
if(v == val[o]){
cnt[o]++, size[o]++;
splay(o, );
return;
}
bool b = v>val[o];
if(!ch[o][b]){
ch[o][b] = ++num_node;
cnt[ch[o][b]] = size[ch[o][b]] = ;
val[ch[o][b]] = v, fa[ch[o][b]] = o;
splay(ch[o][b], );
return;
}
o = ch[o][v>val[o]];
}
}
inline void Find(int v){
for(int o = root; o; o = ch[o][v>val[o]]){
if(val[o] == v){ splay(o, ); return; }
if(!ch[o][v>val[o]]) return;
}
}
inline void Delete(int v){
Find(v);
if(val[root] != v) return;
int o = root;
if(cnt[o] > ){ --cnt[o],--size[o]; return; }
if(!ch[o][] && !ch[o][]){ root = , fa[root] = ; return; }
if(!ch[o][]){ root = ch[o][], fa[root] = ; return; }
if(!ch[o][]){ root = ch[o][], fa[root] = ; return; }
int l_max = ch[root][];
while(ch[l_max][]) l_max = ch[l_max][];
splay(l_max, root);
ch[l_max][] = ch[root][];
fa[ch[root][]] = l_max;
fa[l_max] = ;
int pre_root = root;
root = l_max;
clear(pre_root);
}
inline int Rnk(int x){
Find(x);
return size[ch[root][]] + ;
}
inline int Kth(int k){
for(int o = root; o;){
if(size[ch[o][]] >= k) o = ch[o][];
else if(size[ch[o][]] + cnt[o] < k){
k -= size[ch[o][]] + cnt[o];
o = ch[o][];
}
else{
splay(o,);
return val[o];
}
}
}
inline int Pre(int v){
Insert(v);
int o = ch[root][];
while(ch[o][]) o = ch[o][];
int ans = val[o];
Delete(v);
return ans;
}
inline int Nxt(int v){
Insert(v);
int o = ch[root][];
while(ch[o][]) o = ch[o][];
int ans = val[o];
Delete(v);
return ans;
}
}qxz;
int main(){
// freopen(".in","r",stdin);
n = read();
for(int i = ; i <= n; ++i){
opt = read(), x = read();
if(opt==) qxz.Insert(x);
if(opt==) qxz.Delete(x);
if(opt==) printf("%d\n",qxz.Rnk(x));
if(opt==) printf("%d\n",qxz.Kth(x));
if(opt==) printf("%d\n",qxz.Pre(x));
if(opt==) printf("%d\n",qxz.Nxt(x));
}
return ;
}
「Splay」普通平衡树模板的更多相关文章
- 「Splay」区间翻转
传送门:>Here< 解法分析 用splay来维护这个序列. 一直没有搞明白的是,这里的splay的节点究竟维护的是什么?是权值吗?肯定不是,因为区间是会翻转的,如果维护权值的话很快平衡树 ...
- Solution -「LOCAL」ZB 平衡树
\(\mathcal{Description}\) OurOJ. 维护一列二元组 \((a,b)\),给定初始 \(n\) 个元素,接下来 \(m\) 次操作: 在某个位置插入一个二元组: 翻 ...
- 「luogu3380」【模板】二逼平衡树(树套树)
「luogu3380」[模板]二逼平衡树(树套树) 传送门 我写的树套树--线段树套平衡树. 线段树上的每一个节点都是一棵 \(\text{FHQ Treap}\) ,然后我们就可以根据平衡树的基本操 ...
- 「luogu3402」【模板】可持久化并查集
「luogu3402」[模板]可持久化并查集 传送门 我们可以用一个可持久化数组来存每个节点的父亲. 单点信息更新和查询就用主席树多花 一个 \(\log\) 的代价来搞. 然后考虑如何合并两个点. ...
- SpringBoot图文教程10—模板导出|百万数据Excel导出|图片导出「easypoi」
有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...
- Note -「多项式」基础模板(FFT/NTT/多模 NTT)光速入门
进阶篇戳这里. 目录 何为「多项式」 基本概念 系数表示法 & 点值表示法 傅里叶(Fourier)变换 概述 前置知识 - 复数 单位根 快速傅里叶正变换(FFT) 快速傅里叶逆变换(I ...
- 「SCOI2014」方伯伯的 OJ 解题报告
「SCOI2014」方伯伯的 OJ 和列队有点像,平衡树点分裂维护即可 但是需要额外用个set之类的对编号查找点的位置 插入完了后记得splay,删除时注意特判好多东西 Code: #include ...
- 「NOI2004」「LuoguP1486」郁闷的出纳员
Descrption OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调 ...
- 「数据结构」Link-Cut Tree(LCT)
#1.0 简述 #1.1 动态树问题 维护一个森林,支持删除某条边,加入某条边,并保证加边.删边之后仍然是森林.我们需要维护这个森林的一些信息. 一般的操作有两点连通性,两点路径权值和等等. #1.2 ...
随机推荐
- 关于oracle设置主键自增的问题
关于orcale设置主键自增的问题 关于主键Oracle中并没有提供一个直接的语句设置,对于这个oralce一般都是用序列和触发器来实现 一下又两种方法来实现 一 ,不使用触发器 创建序列: crea ...
- net core 小坑杂记之配置文件读取 02 (控制器里读)
上次更新博客的时候提到了如何在EF的上下文里读取配置,这次介绍一下在控制器里如何读取. 先说一种简单易懂的: 首先以键值对的形式在appsettings里添加一条配置信息,接着Startup里注入配置 ...
- 每周分享之JS数组的使用
数组,一堆数字归为一组,就是一个数组,一堆对象放在一个组里,也是一个数组,概念很容易懂,说白了就是一个有限集合. JS数组的语法无法两种,插入和移除(语法自行科普).用处挺常见的,既然数组是一个集合, ...
- Vue基础(ES6)
起步 1.扎实的HTML/CSS/Javascript基本功,这是前置条件. 2.不要用任何的构建项目工具,只用最简单的<script>,把教程里的例子模仿一遍,理解用法.不推荐上来就 ...
- [2017BUAA软工助教]团队alpha得分总表
一.累计得分 项目 介绍 采访 贡献分 功能 技术 α例会 α发布 α测试 α展示 α事后 合计 满分 10 10 10 10 10 50 10 10 150 10 280 hotcode5 10 9 ...
- jdk环境变量配置注意事项
cmd 运行java -version 显示错误 Registry key 'Software\JavaSoft\Java Runtime Environment\CurrentVersion'has ...
- oracle导出用户下单表或者多表,导入到别的服务器用户下
导出 exp 用户名/密码 file=存放dmp的名称的目录 statistics=none tables =(表名,表名,表名) exp creditfw/credit file=d:\te ...
- Linux 查找文件命令 find whereis locate
Linux 有三个查找文件的命令:find, whereis, locate 其中find 不常用,whereis与locate经常使用,因为find命令速度较慢,因为whereis与locate是利 ...
- java学习之—递归实现变位字
/** * 递归实现变位字 * Create by Administrator * 2018/6/20 0020 * 上午 10:23 **/ public class AnagramApp { st ...
- python之路--线程的其他方法
一 . current_thread的用法 import threading import time from threading import Thread, current_thread def ...