口诀:

$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」普通平衡树模板的更多相关文章

  1. 「Splay」区间翻转

    传送门:>Here< 解法分析 用splay来维护这个序列. 一直没有搞明白的是,这里的splay的节点究竟维护的是什么?是权值吗?肯定不是,因为区间是会翻转的,如果维护权值的话很快平衡树 ...

  2. Solution -「LOCAL」ZB 平衡树

    \(\mathcal{Description}\)   OurOJ.   维护一列二元组 \((a,b)\),给定初始 \(n\) 个元素,接下来 \(m\) 次操作: 在某个位置插入一个二元组: 翻 ...

  3. 「luogu3380」【模板】二逼平衡树(树套树)

    「luogu3380」[模板]二逼平衡树(树套树) 传送门 我写的树套树--线段树套平衡树. 线段树上的每一个节点都是一棵 \(\text{FHQ Treap}\) ,然后我们就可以根据平衡树的基本操 ...

  4. 「luogu3402」【模板】可持久化并查集

    「luogu3402」[模板]可持久化并查集 传送门 我们可以用一个可持久化数组来存每个节点的父亲. 单点信息更新和查询就用主席树多花 一个 \(\log\) 的代价来搞. 然后考虑如何合并两个点. ...

  5. SpringBoot图文教程10—模板导出|百万数据Excel导出|图片导出「easypoi」

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...

  6. Note -「多项式」基础模板(FFT/NTT/多模 NTT)光速入门

      进阶篇戳这里. 目录 何为「多项式」 基本概念 系数表示法 & 点值表示法 傅里叶(Fourier)变换 概述 前置知识 - 复数 单位根 快速傅里叶正变换(FFT) 快速傅里叶逆变换(I ...

  7. 「SCOI2014」方伯伯的 OJ 解题报告

    「SCOI2014」方伯伯的 OJ 和列队有点像,平衡树点分裂维护即可 但是需要额外用个set之类的对编号查找点的位置 插入完了后记得splay,删除时注意特判好多东西 Code: #include ...

  8. 「NOI2004」「LuoguP1486」郁闷的出纳员

    Descrption OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调 ...

  9. 「数据结构」Link-Cut Tree(LCT)

    #1.0 简述 #1.1 动态树问题 维护一个森林,支持删除某条边,加入某条边,并保证加边.删边之后仍然是森林.我们需要维护这个森林的一些信息. 一般的操作有两点连通性,两点路径权值和等等. #1.2 ...

随机推荐

  1. Windows下如何更新 CodeBlocks 中的 MinGW 使其支持新版本 C++

    转自:http://blog.csdn.net/wtfmonking/article/details/17487705 虽然 CodeBlocks16.01 已经是最新版了,但其中的 MinGW 仍然 ...

  2. POJ - 3264 线段树模板题 询问区间最大最小值

    这是线段树的一个模板题,给出一串数字,然后询问区间的最大最小值. 这个其实很好办,只需把线段树的节点给出两个权值,一个是区间的最小值,一个是区间的最大值,初始化为负无穷和正无穷,然后通过不断地输入节点 ...

  3. Day1 初步认识Python

    天气有点阴晴不定~ (截图来自----------金角大王) 1.学习了计算机概论(CPU/Memory/Disk,memory的存在是为了解决信息传输产生的时延) CPU:精简指令集(RISC)-- ...

  4. Java基础之一反射

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))   一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够 ...

  5. scrapy之持久化存储

    scrapy之持久化存储 scrapy持久化存储一般有三种,分别是基于终端指令保存到磁盘本地,存储到MySQL,以及存储到Redis. 基于终端指令的持久化存储 scrapy crawl xxoo - ...

  6. 【学习总结】Git学习-参考廖雪峰老师教程九-使用码云

    学习总结之Git学习-总 目录: 一.Git简介 二.安装Git 三.创建版本库 四.时光机穿梭 五.远程仓库 六.分支管理 七.标签管理 八.使用GitHub 九.使用码云 十.自定义Git 期末总 ...

  7. PHP单元测试PHPUnit

    配置说明 1.全局安装phpunit命令脚本 1 2 3 4 5 $ wget https://phar.phpunit.de/phpunit-7.0.phar $ chmod +x phpunit- ...

  8. [转帖]BRD、MRD 和 PRD

    来源: https://www.zhihu.com/question/19655491 BRD 商业需求文档 Business Requirement Document MRD 市场需求文档 Mark ...

  9. select非group by字段的方法

    只需要将非group by字段放进函数中即可:

  10. Angular ngRepea

    <!DOCTYPE html><html ng-app><head lang="en"> <meta charset="UTF- ...