转自

无旋版 $Treap$。

只需要两个操作即可达到 $splay$ 的所有功能

1、$split$

它的主要思想就是把一个 $Treap$ 分成两个。

$split$ 操作有两种类型,一种是按照权值分配,一种是按前 k 个分配。

第一种就是把所有小于 k 的权值的节点分到一棵树中,第二种是把前 k 个分到一个树里。

权值版:

 void split(int o,int k,int &x,int &y){ //这里的x,y分别是将以o为根的树切开后第一个新子树的根和第二个新子树的根
if(!o) x=y=;
else {
if(val[o]<=k)
x=o,split(ch[o][],k,ch[o][],y);
else
y=o,split(ch[o][],k,x,ch[o][]);
pushup(o);
}
}

对于我们遍历到每一个点,假如它的权值小于k,那么它的所有左子树,都要分到左边的树里,然后遍历它的右儿子。假如大于k,把它的所有右子树分到右边的树里,遍历左儿子。

因为它的最多操作次数就是一直分到底,效率就是 $O(logn)$。

对于前k个版的,就是像找第k大的感觉。每次减掉sze

void split(int now,int k,int &x,int &y){
if (!now) x=y=;
else{
if (k<=siz[ch[now][]])
y=now,split(ch[now][],k,x,ch[now][]);
else
x=now,split(ch[now][],k-sze[ch[now][]]-,ch[now][],y);
pushup(now);
}
}

2、$merge$

这个就是把两个 $Treap$ 合成一个,保证第一个的权值小于第二个。

因为第一个 $Treap$ 的权值都比较小,我们比较一下它的 $prio$ (优先级),假如第一个的 $prio$ 小,我们就可以直接保留它的所有左子树,接着把第一个 $Treap$ 变成它的右儿子。反之,我们可以保留第二棵的所有右子树,指针指向左儿子。

你可以把这个过程形象的理解为在第一个 $ Treap$ 的右子树上插入第二个树,也可以理解为在第二个树的左子树上插入第一棵树。因为第一棵树都满足小于第二个树,所以就变成了比较 $prio$ 来确定树的形态。

也就是说,我们其实是遍历了第一个$Treap$ 的根->最大节点,第二个$Treap$的根->最小节点,也就是 $O(logn)$

int merge(int x,int y){
if(!x or !y) return x+y;
if(prio[x]<prio[y]){
ch[x][]=merge(ch[x][],y);
pushup(x);
return x;
}
else{
ch[y][]=merge(x,ch[y][]);
pushup(y);
return y;
}
}

下面我们就可以通过这两个基本的东西实现各种各样的操作了。

3、insert

插入一个权值为 $k$ 的点,把树按照 $k$ 的权值 $split$ 成两个,再 $merge$ 回去。

4、remove

删除权值为 $k$ 的点,把树按照 $k$ 分成两个$a,b$ 再把$a$ 按照 $k-1$ 分成$c,d$。把$d$ 的两个儿子 $merge$起来,再 $merge(merge(c,d),b)$

void remove(int k){
int x,y,z;
split(Root,k,x,y);
split(x,k-,x,z);
z=merge(ch[z][],ch[z][]);
Root=merge(x,merge(z,y));
}

其它见代码

// 普通平衡树 fhq_Treap
// By YoungNeal
#include<cstdio>
#include<cstdlib>
#define N 100005
#define inf 0x3f3f3f3f int Root;
int n,opt,x,tot;
int val[N],prio[N];
int sze[N],ch[N][]; void pushup(int o){
sze[o]=sze[ch[o][]]+sze[ch[o][]]+;
} void split(int o,int k,int &x,int &y){
if(!o) x=y=;
else {
if(val[o]<=k)
x=o,split(ch[o][],k,ch[o][],y);
else
y=o,split(ch[o][],k,x,ch[o][]);
pushup(o);
}
} int merge(int x,int y){
if(!x or !y) return x+y;
if(prio[x]<prio[y]){
ch[x][]=merge(ch[x][],y);
pushup(x);
return x;
}
else{
ch[y][]=merge(x,ch[y][]);
pushup(y);
return y;
}
} int newnode(int v){
sze[++tot]=;
val[tot]=v;
prio[tot]=rand();
return tot;
} void insert(int k){
int x,y;
split(Root,k,x,y);
Root=merge(merge(x,newnode(k)),y);
} void remove(int k){
int x,y,z;
split(Root,k,x,y);
split(x,k-,x,z);
z=merge(ch[z][],ch[z][]);
Root=merge(x,merge(z,y));
} void kthrank(int k){
int x,y;
split(Root,k-,x,y);
printf("%d\n",sze[x]+);
Root=merge(x,y);
} int rank(int o,int k){
if(sze[ch[o][]]==k-) return val[o];
if(sze[ch[o][]]>=k) return rank(ch[o][],k);
return rank(ch[o][],k-sze[ch[o][]]-);
} void prev(int k){
int x,y;
split(Root,k-,x,y);
printf("%d\n",rank(x,sze[x]));
Root=merge(x,y);
} void nxt(int k){
int x,y;
split(Root,k,x,y);
printf("%d\n",rank(y,));
Root=merge(x,y);
} signed main(){
scanf("%d",&n);
while(n--){
scanf("%d%d",&opt,&x);
if(opt==) insert(x);
if(opt==) remove(x);
if(opt==) kthrank(x);
if(opt==) printf("%d\n",rank(Root,x));
if(opt==) prev(x);
if(opt==) nxt(x);
}
return ;
}

5、区间操作

对于翻转区间 $[l,r]$,我们可以先把区间 $[1,l-1]$ $split$ 出来,再把 $[l,r]$ $split$ 出来就行了。注意 $lazy$ 标记及时清除。

// 文艺平衡树 fhp_Treap
// By YoungNeal
#include<ctime>
#include<cstdio>
#include<cstdlib>
#define N 100005 int Root;
int lazy[N];
int n,m,cnt;
int val[N],sze[N];
int ch[N][],prio[N]; void pushup(int o){
sze[o]=sze[ch[o][]]+sze[ch[o][]]+;
} void pushdown(int o){
if(!lazy[o] or !o) return;
ch[o][]^=ch[o][]^=ch[o][]^=ch[o][];
lazy[ch[o][]]^=;
lazy[ch[o][]]^=;
lazy[o]=;
} void split(int o,int k,int &x,int &y){
if(!o) x=y=;
else{
pushdown(o);
if(k>sze[ch[o][]]) x=o,split(ch[o][],k-sze[ch[o][]]-,ch[o][],y);
else y=o,split(ch[o][],k,x,ch[o][]);
pushup(o);
}
} int merge(int x,int y){
if(!x or !y) return x+y;
pushdown(x); pushdown(y);
if(prio[x]<prio[y]){
ch[x][]=merge(ch[x][],y);
pushup(x);
return x;
}
else{
ch[y][]=merge(x,ch[y][]);
pushup(y);
return y;
}
} int newnode(int v){
val[++cnt]=v;
sze[cnt]=;
prio[cnt]=rand();
return cnt;
} void res(int l,int r){
int a,b,c,d;
split(Root,r,a,b);
split(a,l-,c,d);
lazy[d]^=;
Root=merge(merge(c,d),b);
} void dfs(int now){
if(!now) return;
pushdown(now);
dfs(ch[now][]);
printf("%d ",val[now]);
dfs(ch[now][]);
} signed main(){
srand(time());
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
Root=merge(Root,newnode(i));
//printf("Root=%d\n",Root);
for(int x,y,i=;i<=m;i++){
scanf("%d%d",&x,&y);
res(x,y);
//printf("i=%d\n",i);
//dfs(Root);
}
//printf("Root=%d\n",Root);
dfs(Root);
return ;
}

[总结] fhq_Treap 学习笔记的更多相关文章

  1. fhq_treap 学习笔记

    前言:昨天写NOIp2017队列,写+调辗转了3h+,不知道怎么的,就点进了一个神仙的链接,便在今日学习了神仙的fhq_treap. 简介:fhq_treap功能强大,支持splay支持的所有操作,代 ...

  2. Treap与fhq_Treap学习笔记

    1.普通Treap 通过左右旋来维护堆的性质 左右旋是不改变中序遍历的 #include<algorithm> #include<iostream> #include<c ...

  3. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  4. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  5. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  6. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  7. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  8. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  9. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

随机推荐

  1. Linux磁盘分区-rpm-yum

    一.磁盘分区 1.开启Linux系统前添加一块大小为15G的SCSI硬盘 2.开启系统,右击桌面,打开终端 3.为新加的硬盘分区,一个主分区大小为5G,剩余空间给扩展分区,在扩展分区上划分1个逻辑分区 ...

  2. scrapy爬取全部知乎用户信息

    # -*- coding: utf-8 -*- # scrapy爬取全部知乎用户信息 # 1:是否遵守robbots_txt协议改为False # 2: 加入爬取所需的headers: user-ag ...

  3. Iframe父页面与子页面之间的相互调用

    iframe元素就是文档中的文档. window对象: 浏览器会在其打开一个HTML文档时创建一个对应的window对象.但是,如果一个文档定义了一个或者多个框架(即:包含一个或者多个frame或者i ...

  4. (CLR-Via-C#) 类型基础

    CLR要求每个类型最终都派生自System.Object Object提供的公共方法: Equals: 如果两个对象具有相同的值,就返回true GetHashCode: 返回对象的哈希码 ToStr ...

  5. linux搭建node环境超详细教程

    linux 环境搭建详细步骤 1.访问官方网址:https://nodejs.org/en/download/ 2.选择和你服务器版本相关的压缩包,复制下载链接 3.服务器登录ssh,(这里我用的服务 ...

  6. iframe 里的高度适应的问题

    iframe 这个东西功能是很强大,但是有一个巨大的问题就是高度自适应的问题: 不过这个问题,百度或者谷歌上有很多解决办法,但是,很多时候都有兼容性问题: 所有我就每个方法都试了一遍,终于找到了一个 ...

  7. Apache 安装与配置(WIN10)

    本地坏境:windows 10 Pro 1709 Apache版本:httpd-2.4.32-Win64-VC15 Apache下载地址:https://www.apachelounge.com/do ...

  8. [LeetCode] Sliding Window Median 滑动窗口中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  9. 深入解析 SQL Server 高可用镜像实现原理

    作者:郭忆 本文由 网易云 发布. SQL Server 是 windows 平台 .NET 架构下标配数据库解决方案,与 Oracle.MySQL 共同构成了 DB-Engines Ranking ...

  10. Docker And Swarm Mode(一)

    (一)节点的创建和配置 前言  虽然工作中一直在用Docker和Docker Swarm,但是总感觉有点陌生,总想自己亲手来写写和配置Docker 容器相关的事情,这篇文章主要是参考了Los Tech ...