口诀:

$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. 六、Xadmin忘记密码

    1.如果用的是django自带的User模块,忘记了超级用户的密码,可以通过以下方法找回密码: 终端进入项目根目录,然后输入如下命令: python manage.py shell 然后在python ...

  2. 从HelloWorld开始学习.NET Core

    1.首先创建一个项目文件夹,如E:\CoreProjects 使用cmd命令进入到新建的文件夹中 2.创建一个HelloWorld项目 命令:dotnet new console -o hellowo ...

  3. Python_每日习题_0004_一年中的第几天

    # 题目 输入某年某月某日,判断这一天是这一年的第几天? # 程序分析 特殊情况,闰年时需考虑二月多加一天: def isLeapYear(y): return (y%400==0 or (y%4== ...

  4. 小L的试卷

    题目描述 小L期末考试结束,高高兴兴放假回家了,可是那么多试卷,老师还要加班批改,有n份试卷由k个老师批改,n份试卷进行了密封编号,由于试卷上的做题情况和书写的规范程序不一样,批改不同的试卷用时也可能 ...

  5. rest-framework解析器,url控制,分页,响应器,渲染器,版本控制

    解析器 1.json解析器 发一个json格式的post请求.后台打印: request_data---> {'title': '北京折叠'} request.POST---> <Q ...

  6. PyCharm中快速给选中的代码加上{}、<>、()、[]

    快捷键Ctrl + Shift + S 呼出下图所示界面:

  7. python文件封装成*.exe文件(单文件和多文件)

    环境:win10 64位  python3.7 单*.py文件打包Python GUI:程序打包为exe 一.安装Pyinstaller,命令pip install Pyinstaller,(大写的P ...

  8. spark单击 搭建

    http://files.cnblogs.com/files/yxnyd/spark.zip

  9. iphone 分辨率相关

    iPhone 1G 320x480 iPhone 3G 320x480 iPhone 3GS 320x480 iPhone 4 640x960 iPhone 4S 640x960 iPhone 5 6 ...

  10. HDU 3900 Unblock Me

    题目:Unblock Me 链接:Here 题意:一个游戏,看图就基本知道题意了,特殊的是:1. 方块长度为3或2,宽度固定是1.2. 地图大小固定是6*6,从0开始. 3. 出口固定在(6,2).4 ...