「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 ...
随机推荐
- prometeus, grafana部署以及监控mysql
什么是普罗米修斯? Prometheus是一个最初在SoundCloud上构建的开源系统监视和警报工具包 .自2012年成立以来,许多公司和组织都采用了Prometheus,该项目拥有一个非常活跃的开 ...
- 【转载】SQL中inner join、outer join和cross join的区别
对于SQL中inner join.outer join和cross join的区别很多人不知道,我也是别人问起,才查找资料看了下,跟自己之前的认识差不多, 如果你使用join连表,缺陷的情况下是inn ...
- elasticsearch数据输入和输出
Elastcisearch 是分布式的 文档 存储.它能存储和检索复杂的数据结构–序列化成为JSON文档–以 实时 的方式. 换句话说,一旦一个文档被存储在 Elasticsearch 中,它就是可以 ...
- 【kindle笔记】之 《犬夜叉》-2017-12-26
[kindle笔记]读书记录-总 2017-12-26 <犬夜叉> 买kindle的初衷是看计算机工具书看得眼快瞎了,我弟弟推荐给我的Linux系列<鸟叔私房菜> 真的是深思熟 ...
- HDU 2001 计算两点间的距离
http://acm.hdu.edu.cn/showproblem.php?pid=2001 Problem Description 输入两点坐标(X1,Y1),(X2,Y2),计算并输出两点间的距离 ...
- java不同的包下相同的类名的问题与解决办法
Java中的类以包进行分类组织,当程序中需要用到某个包下的类时,可以以该类的全限定名进行引用.这样,不同的包中的类就可以同名,不会产生混淆. 但是这样就可能导致引用的时候会产生一些问题. 第一个问题, ...
- java 浅拷贝和深拷贝 对象克隆clone
分一下几点讨论: 为什么要克隆? 如何实现克隆 浅克隆和深克隆 解决多层克隆问题 总结 一:为什么要克隆? 大家先思考一个问题,为什么需要克隆对象?直接new一个对象不行吗? 答案是:克隆的对象可能包 ...
- Microsoft Visual Studio Ultimate 2013密钥
Visual Studio Ultimate 2013 KEY(密钥):BWG7X-J98B3-W34RT-33B3R-JVYW9Visual Studio Premium 2013 KEY(密钥): ...
- 连接mysql 出现 1005 error(150) , error(121)的错误
1.显示不能创建表 出现150错误 将检查是因为 我的user 表示拷贝过来的所以它设置的编码格式是utf-8 而我又新创建的表没有添加编码格式,所以它认为这两个关联的表之间的编码格式不匹配. 2.出 ...
- java学习之—栈
/** * 栈 * Create by Administrator * 2018/6/11 0011 * 上午 10:20 **/ public class StackX { private int ...