但凡打过平衡树的应该都知道\(\huge{二逼平衡树}\)这道题,抄了两个小时的splay版题解,然后发现了\(\huge\color{maroon}FHQ treap\):

$\large\color{green}这是splay$
struct jjtree
{
inline void up(rint x){sz[x]=sz[son[x][0]]+sz[son[x][1]]+cnt[x];}
inline bool so(rint x){return x==son[fa[x]][1];}
inline void clear(rint x){fa[x]=son[x][0]=son[x][1]=cnt[x]=v[x]=sz[x]=0;}
inline void xuan(rint x){
rint y=fa[x],z=fa[y];bool op=so(x);
son[y][op]=son[x][op^1];if(son[y][op])fa[son[y][op]]=y;
son[x][op^1]=y,fa[y]=x;if(z)son[z][y==son[z][1]]=x;fa[x]=z;
up(x),up(y);
}
inline void splay(rint x,rint y=0){
if(!y)rt=x;
while(fa[x]!=y){
rint k1=fa[x];
if(fa[k1]!=y)xuan(so(x)==so(k1)?k1:x);
xuan(x);
}
}
inline void insert(int x){
if(!rt){
v[++tot]=x;
++cnt[tot];rt=tot;up(rt);return;
}
int now=rt,f=0;
while(1){
// cout<<now<<endl;
if(v[now]==x){
++cnt[now];up(now);up(f);splay(now);return;
}
f=now,now=son[now][x>v[now]];
if(!now){
v[++tot]=x,++cnt[tot],fa[tot]=f;
son[f][x>v[f]]=tot;up(tot),up(f),splay(tot);
return;
}
}
}
inline int rk(int x){
int ans=0,now=rt;
while(1){
if(x<v[now])now=son[now][0];
else{
ans+=sz[son[now][0]];
if(!now)return ans+1;
if(x==v[now])return splay(now),ans+1;
ans+=cnt[now],now=son[now][1];
}
}
}
inline int kth(int k){
int now=rt;
while(1){
if(son[now][0]&&k<=sz[son[now][0]])now=son[now][0];
else{
k-=sz[son[now][0]]+cnt[now];
if(k<=0)return splay(now),v[now];
now=son[now][1];
}
}
}
inline int pre(){
int now=son[rt][0];
if(!now)return 0;
while(son[now][1])now=son[now][1];
splay(now);
return now;
}
inline int nxt(){
int now=son[rt][1];
if(!now)return 0;
while(son[now][0])now=son[now][0];
splay(now);
return now;
}
inline void del(int k){
rk(k);
// if(v[rt]!=k)return;
if(cnt[rt]>1)return --cnt[rt],up(rt),(void)(0);
if(!son[rt][0]&&!son[rt][1])return clear(rt),rt=0,(void)0;
if(!son[rt][0]){
int now=rt;rt=son[rt][1];fa[rt]=0;clear(now);return;
}
if(!son[rt][1]){
int now=rt;rt=son[rt][0];fa[rt]=0;clear(now);return;
}
int now=rt,x=pre();
fa[son[now][1]]=x;son[x][1]=son[now][1];
clear(now);up(rt);
}
}tr;

$\large{总长91行}$

$\large\color{green}这是FHQ treap$
struct jj{
int son[N][2],sz[N],v[N],id[N],tot,rt;
inline void up(int x){sz[x]=sz[son[x][0]]+sz[son[x][1]]+1;}
inline int ne(int x){return sz[++tot]=1,v[tot]=x,id[tot]=rand(),tot;}
inline int he(int x,int y){
if(!x||!y)return x^y;
if(id[x]<id[y]){return son[x][1]=he(son[x][1],y),up(x),x;}
return son[y][0]=he(x,son[y][0]),up(y),y;
}
inline void fen(int now,int k,int &x,int &y){
if(!now)x=y=0;
else{
if(k>=v[now])x=now,fen(son[now][1],k,son[now][1],y);
else y=now,fen(son[now][0],k,x,son[now][0]);
up(now);
}
}
inline int kth(int now,int k){
while(1){
if(k<=sz[son[now][0]])now=son[now][0];
else if(k==sz[son[now][0]]+1)return now;
else k-=sz[son[now][0]]+1,now=son[now][1];
}
}
inline void ins(int k){
int x,y;
fen(rt,k,x,y),rt=he(he(x,ne(k)),y);
}
inline void del(int k){
int x,y,z;
fen(rt,k,x,y),fen(x,k-1,x,z);
z=he(son[z][0],son[z][1]),rt=he(he(x,z),y);
}
inline int rk(int k){
int x,y,ans;
fen(rt,k-1,x,y);ans=sz[x]+1;
return rt=he(x,y),ans;
}
inline int pre(int k){
int x,y,ans;
fen(rt,k-1,x,y);ans=v[kth(x,sz[x])];
return rt=he(x,y),ans;
}
inline int nxt(int k){
int x,y,ans;
fen(rt,k,x,y);ans=v[kth(y,1)];
return rt=he(x,y),ans;
}
}tr[2];

$\large{总长48行}$

\[\]
\[\]
\[\]
\[\]

终于知道什么是$$\huge\color{seagreen}{相见恨晚}$$


\[\]
\[\]
\[\]

闲言少叙,开始摞码

\[\]
\[\]
\[\]

\(\huge\color{purple}{FHQ treap}\)

\[\]
\[\]

\(\large \color{salmon}{即无旋treap,同时维护着堆和二叉树的性质,支持splay、treap可支持的一切操作,而且更方便}\)

\[\]

\(\large\color{maroon}维护信息其他平衡树基本相同\)

struct jj{
int son[N][2],sz[N],tot,rt,id[N],v[N];
//son[i][0]->ls(i),son[i][1]-> rs(i)
//sz[i]-> 以i为根节点的树的大小
//id[i]-> rand()出来的,用来维护堆的性质
//v[i] i点存的权值
//tot-> 所有存在过的点的个数,主要用来新建一个点
//rt -> 这棵树的根
inline void up(int x){sz[x]=sz[son[x][0]]+sz[son[x][1]]+1;}//update
inline int ne(int x){return sz[++tot]=1,v[tot]=x,id[tot]=rand(),tot;}//新建一个点
}tr[2];
\[\]
\[\]
\[\]

\(\large \color{maroon}{FHQ只需要两个操作:合并与分裂}\)

\(\large{合并}:\)

\[\]

\(\large\color{salmon} 合并,即将两颗合法的treap(x和y,而且要保证x中的任何一个元素都小于等于y中的任意元素)合并成为一棵树。\)

\(\large\color{salmon} 根据随机给的id,为了保持堆的性质,让id小的在上面(喜欢让id大的在上面也行 , 只要全局保持同意即可)\)

inline int he(int x,int y){
if(!x||!y)return x^y;
if(id[x]<id[y])return son[x][1]=he(son[x][1],y),up(x),x;
return son[y][0]=he(x,son[y][0]),up(y),y;
}
\[\]

\(\large{分裂:}\)

\[\]

\(\large\color{salmon}{把一棵树分成小于等于k(x),和大于k(y)的两部分)}\)

inline void fen(int now,int k,int &x,int &y){
if(!now)x=y=0;//叶子节点,不要忘记清空
else{
if(k>=v[now])x=now,fen(son[now][1],k,son[now][1],y);//now及其左子树都可以归到x中,然后继续向下fen
else y=now,fen(son[now][0],k,x,son[now][0]);//now及其右字数都可以归到y中,继续fen
up(now);//别忘up
}
}
\[\]
\[\]

\(\large\color{maroon}{会了合并与分裂就可以进行各种操作了}\)

\[\]

\(\large \cal{insert}:\)

\(\large\color{salmon}以k为界定值,将树分为两部分x和y,并在x,y中间插入一个权值为k的节点,将他们合并起来\)

inline void ins(int k){
int x,y;
fen(rt,k,x,y),rt=he(he(x,ne(k)),y);
}
\[\]

\(\large \cal{delete}:\)

\(\large\color{salmon}以k为界定值分为x,y,再以k-1为界定值将x分为x,z,那么z中所有节点都是权值为k,删除z根节点,再将他们合并起来即可\)

inline void del(int k){
int x,y,z;
fen(rt,k,x,y),fen(x,k-1,x,z);
z=he(son[z][0],son[z][1]),rt=he(he(x,z),y);
}
\[\]

\(\large \cal{kth}:\)

\(\large\color{salmon}在以now为根的树中,排名为k的节点\)

inline int kth(int now,int k){
while(1){
if(k<=sz[son[now][0]])now=son[now][0];
else if(k==sz[son[now][0]]+1)return now;
else k-=sz[son[now][0]]+1,now=son[now][1];
}
}
\[\]

\(\large \cal{rank}:\)

inline int rk(int k){
int x,y,ans;
fen(rt,k-1,x,y);ans=sz[x]+1;
return rt=he(x,y),ans;
}
\[\]

\(\large \cal{pre\ and \ next}:\)

inline int pre(int k){
int x,y,ans;
fen(rt,k-1,x,y);ans=v[kth(x,sz[x])];
return rt=he(x,y),ans;
}
inline int nxt(int k){
int x,y,ans;
fen(rt,k,x,y);ans=v[kth(y,1)];
return rt=he(x,y),ans;
}
\[\huge\color{purple}{FHQ \ treap \ 好用 \ 爱用 \ 天天用 }
\]

FHQ treap(再见splay------)的更多相关文章

  1. LOJ#105. 文艺平衡树(FHQ Treap)

    题面 传送门 题解 \(FHQ\ Treap\)比起\(Splay\)还是稍微好写一点--就是老是忘了要下穿标记-- //minamoto #include<bits/stdc++.h> ...

  2. NOI 2002 营业额统计 (splay or fhq treap)

    Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每 ...

  3. Luogu P3391 文艺平衡树(Splay or FHQ Treap)

    这道题要求区间反转...好东西.. 对于Splay:把l-1旋到根,把r+1旋到根的右儿子,这样r+1的左儿子就是整个区间了,然后对这个区间打个tg 注意要插-Inf和Inf到树里面,防止越界,坐标要 ...

  4. 平衡树合集(Treap,Splay,替罪羊,FHQ Treap)

    今天翻了翻其他大佬的博客,发现自己有些...颓废... 有必要洗心革面,好好学习 序:正常的BST有可能退化,成为链,大大降低效率,所以有很多方法来保持左右size的平衡,本文将简单介绍Treap,S ...

  5. 平衡树(Splay、fhq Treap)

    Splay Splay(伸展树)是一种二叉搜索树. 其复杂度为均摊\(O(n\log n)\),所以并不可以可持久化. Splay的核心操作有两个:rotate和splay. pushup: 上传信息 ...

  6. 【数据结构】平衡树splay和fhq—treap

    1.BST二叉搜索树 顾名思义,它是一棵二叉树. 它满足一个性质:每一个节点的权值大于它的左儿子,小于它的右儿子. 当然不只上面那两种树的结构. 那么根据性质,可以得到该节点左子树里的所有值都比它小, ...

  7. 「FHQ Treap」学习笔记

    话说天下大事,就像fhq treap —— 分久必合,合久必分 简单讲一讲.非旋treap主要依靠分裂和合并来实现操作.(递归,不维护fa不维护cnt) 合并的前提是两棵树的权值满足一边的最大的比另一 ...

  8. FHQ Treap摘要

    原理 以随机数维护平衡,使树高期望为logn级别 不依靠旋转,只有两个核心操作merge(合并)和split(拆分) 因此可持久化 先介绍变量 ; int n; struct Node { int v ...

  9. FHQ Treap小结(神级数据结构!)

    首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右 ...

  10. 在平衡树的海洋中畅游(四)——FHQ Treap

    Preface 关于那些比较基础的平衡树我想我之前已经介绍的已经挺多了. 但是像Treap,Splay这样的旋转平衡树码亮太大,而像替罪羊树这样的重量平衡树却没有什么实际意义. 然而类似于SBT,AV ...

随机推荐

  1. 【TypeScript】02 面向对象

    [联合类型] 联合类型(Union Types)可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值. 注意:只能赋值指定的类型,如果赋值其它类型就会报错. var val:strin ...

  2. 从.net开发做到云原生运维(三)——.net core的学习路线

    1. 前言 前面几篇文章主要讲了.net技术相关的基本概念和一些涉及的项目什么,本身也没讲太多底层的技术,这篇文章依旧不讲具体的技术,主要介绍.net技术的学习路线.学习路线也是我18年毕业的时候看到 ...

  3. 中国特供阉割版4090D建议安装最新驱动,据说不然的话会报error:4090和4090D对比

    资料来源: https://www.bilibili.com/video/BV1oa4y127fG/?spm_id_from=333.999.0.0&vd_source=f1d0f27367a ...

  4. 安装wsl的必备操作——开启CPU虚拟化——WslRegisterDistribution failed with error_ 0x8007019e 0x800701b 0x80370102 请启用虚拟机平台

    参考: https://www.cnblogs.com/smdtxz/p/16837946.html https://www.cnblogs.com/wenonly/p/17206040.html h ...

  5. WhaleStudio 2.6正式发布,WhaleTunnel同步性能与连接器数量再创新高!

    在这个数据驱动的大模型时代,数据集成的作用和意义愈发重要.数据不仅仅是信息的载体,更是推动企业决策和创新的关键因素.作为全球最流行的批流一体数据集成工具,WhaleTunnel随着WhaleStudi ...

  6. 性能测试面试题大曝光,让你如何迅速拿下 offer!

    性能测试面试题精选 1. 以前做过性能测试么?请结合例子具体说明性能测试的流程 面试考察点:性能测试的流程 首选做性能测试的需求分析,明确性能测试的目标.范围.场景和性能指标(如响应时间.吞吐量.并发 ...

  7. 同一块石头搬到了两次的List<Map> 转List<dto>的问题

    不多比比 it is shame to talking about this List<Map<String, Object>> maps = reader.readAll() ...

  8. 获取Windows个性化中自带的聚焦锁屏

    想要保存登录屏幕(锁屏界面)的背景图片,可以通过以下脚本一键获取: @echo off setlocal enabledelayedexpansion :: Windows Spotlight 锁屏图 ...

  9. uni-app和vue及微信小程序的异同

    uni-app和vue的区别1.目录不同 uni-app目录依赖原生小程序风格,比如分包的概念 vue中对不同的页面只需要在views文件夹中定义不同组件,然后配置路由跳转就行了,所有页面都是这样, ...

  10. WKCTF RE

    WKCTF so_easy 安卓逆向,关键的check逻辑都在native层里面 主要是很多层的异或操作 除了Z3和爆破想不到其他方法了 from z3 import * src = [ 0xAE, ...