口诀:

$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. 卷积神经网络CNN的意义

    一.选用卷积的原因 局部感知 简单来说,卷积核的大小一般小于输入图像的大小(如果等于则是全连接),因此卷积提取出的特征会更多地关注局部 —— 这很符合日常我们接触到的图像处理.而每个神经元其实没有必要 ...

  2. 一点感悟:《Node.js学习笔记》star数突破1000+

    写作背景 笔者前年开始撰写的<Node.js学习笔记> github star 数突破了1000,算是个里程碑吧. 从第一次提交(2016.11.03)到现在,1年半过去了.突然有些感慨, ...

  3. jqGrid之treeGrid及行拖拽

    单纯的做个小记录 今天做功能用到了jqGrid里面的treeGrid,遇到几个问题,这里做下记录 treeGrid 树表格的应用在官网给出了很直白的例子: 1.http://blog.mn886.ne ...

  4. Baby Coins

    题意 描述 Baby 今天清点自己的百宝箱啦,箱子里有n 种硬币,硬币的面值分别是:val[1],val[2],...,val[n],每种面值的硬币都恰好有2 个. Baby 实在闲的太无聊了,他想从 ...

  5. sso单点登录系统(解决session共享)

    场景:假设一个用户将自己的登录信息提交到后台,如果session保存的信息分布在多台机器上,并且不共享,那么可能导致用户的登录信息出现短暂的丢失,为什么这样讲,因为用户访问服务器中间还要经过负载均衡服 ...

  6. Javascript模板引擎handlebars使用

    源地址:http://rfyiamcool.blog.51cto.com/1030776/1278620 代码示例: <!DOCTYPE html> <html> <he ...

  7. C#复习笔记(4)--C#3:革新写代码的方式(查询表达式和LINQ to object(下))

    查询表达式和LINQ to object(下) 接下来我们要研究的大部分都会涉及到透明标识符 let子句和透明标识符 let子句不过是引入了一个新的范围变量.他的值是基于其他范围变量的.let 标识符 ...

  8. [转帖] bat方式遍历目录内的文件

    https://blog.csdn.net/qq_34924407/article/details/82781956 知识挺好用的 学习一下. #所有文件,包括子目录下的文件 @echo offcd ...

  9. [转帖]FORFILES 的简单介绍。

    FORFILES https://blog.csdn.net/sandy9919/article/details/82932460 命令格式: forfiles.exe /p "D:\备份& ...

  10. mybatis异常解决:class path resource [SqlMapConfig.xml] cannot be opened because it does not exist

    解决方法: 缺失SqlMapConfig.xml文件.