非旋转treap的操作基于split和merge操作,其余操作和普通平衡树一样,复杂度保证方式与旋转treap差不多,都是基于一个随机的参数,这样构出的树树高为\(logn\)

split

作用:将原平衡树分为排名为\([1,k]\),\([k+1,n]\)的两棵平衡树

实现:

1.如果\(x\)左儿子的子树大小\(size[l]==k\),那么\(x\)左儿子即为\([1,k]\)这个平衡树的根,\(x\)本身为另一颗平衡树的根

2.如果\(x\)左儿子的子树大小\(size[l]+1==k\),那么\(x\)为\([1,k]\)这个平衡树的根,\(x\)右儿子为另一颗平衡树的根

3.如果是上述情况,直接把左儿子或右儿子接上去就好

4.否则,递归处理,直到出现这两种情况位置

inline void split(int x,int k,int &a,int &b){
if(!k){a=0;b=x;return ;}
int l=ch[x][0],r=ch[x][1];
if(sz[l]==k)ch[x][0]=0,a=l,b=x;
else if(sz[l]+1==k)ch[x][1]=0,a=x,b=r;
else if(sz[l]>k)split(l,k,a,ch[x][0]),b=x;
else split(r,k-sz[l]-1,ch[x][1],b),a=x;
upd(x);
}

merge

作用:将两棵平衡树合并,合并后参数满足\(heap\)的性质,且满足平衡树性质.

实现:

我们强制\(merge(x,y)\)中\(x\)的所有节点的关键字都小于所有\(y\)的关键字,根据关键字合并即可.

inline int merge(int x,int y){
if(!x||!y)return x+y;
if(key[x]>key[y]){
ch[x][1]=merge(ch[x][1],y);
upd(x);
return x;
}
else{
ch[y][0]=merge(x,ch[y][0]);
upd(y);
return y;
}
}

insert

以\(x\)的前驱为界,拆原树为两棵树,将左树合并到\(x\),再将\(x\)合并到右树

inline void ins(int x){
v[++cnt]=x;key[cnt]=rand();sz[cnt]=1;
int l,r;
split(rt,rank(x)-1,l,r);
rt=merge(merge(l,cnt),r);
}

delet

以\(x\)为界\(split\)原树,删除\(x\)后再合并左右子树

inline void Delet(int x){
int l,r;
split(rt,x,l,r);
split(l,x-1,l,x);
rt=merge(l,r);
}

标记下放

只需在\(merge\),\(split\),\(kth\),\(rank\)函数前下放即可

完整代码:

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=100005;
int ch[N][2],sz[N],key[N],cnt=0,v[N],rt;
inline void upd(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
inline void split(int x,int k,int &a,int &b){
if(!k){a=0;b=x;return ;}
int l=ch[x][0],r=ch[x][1];
if(sz[l]==k)ch[x][0]=0,a=l,b=x;
else if(sz[l]+1==k)ch[x][1]=0,a=x,b=r;
else if(sz[l]>k)split(l,k,a,ch[x][0]),b=x;
else split(r,k-sz[l]-1,ch[x][1],b),a=x;
upd(x);
}
inline int merge(int x,int y){
if(!x||!y)return x+y;
if(key[x]>key[y]){
ch[x][1]=merge(ch[x][1],y);
upd(x);
return x;
}
else{
ch[y][0]=merge(x,ch[y][0]);
upd(y);
return y;
}
}
inline int rank(int k){
int x=rt,ret=1;
while(x){
if(k<=v[x])x=ch[x][0];
else ret+=sz[ch[x][0]]+1,x=ch[x][1];
}
return ret;
}
inline int kth(int k){
int x=rt,sum;
while(x){
sum=sz[ch[x][0]];
if(sum==k-1)return v[x];
if(sum>=k)x=ch[x][0];
else x=ch[x][1],k-=sum+1;
}return 0;
}
inline void ins(int x){
v[++cnt]=x;key[cnt]=rand();sz[cnt]=1;
int l,r;
split(rt,rank(x)-1,l,r);
rt=merge(merge(l,cnt),r);
}
inline void Delet(int x){
int l,r;
split(rt,x,l,r);
split(l,x-1,l,x);
rt=merge(l,r);
}
void work()
{
int n,op,x;
scanf("%d",&n);
while(n--){
scanf("%d%d",&op,&x);
if(op==1)ins(x);
else if(op==2)Delet(rank(x));
else if(op==3)printf("%d\n",rank(x));
else if(op==4)printf("%d\n",kth(x));
else if(op==5)printf("%d\n",kth(rank(x)-1));
else if(op==6)printf("%d\n",kth(rank(x+1)));
}
} int main()
{
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
work();
return 0;
}

关于非旋转treap的学习的更多相关文章

  1. 左偏树 / 非旋转treap学习笔记

    背景 非旋转treap真的好久没有用过了... 左偏树由于之前学的时候没有写学习笔记, 学得也并不牢固. 所以打算写这么一篇学习笔记, 讲讲左偏树和非旋转treap. 左偏树 定义 左偏树(Lefti ...

  2. [NOIP]2017列队——旋转treap/非旋转treap

    Sylvia 是一个热爱学习的女孩子.  前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m.  为了便 ...

  3. 平衡树及笛卡尔树讲解(旋转treap,非旋转treap,splay,替罪羊树及可持久化)

    在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用 ...

  4. [bzoj3173]最长上升子序列_非旋转Treap

    最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为 ...

  5. [Codeforces702F]T-Shirts——非旋转treap+贪心

    题目链接: Codeforces702F 题目大意:有$n$种T恤,每种有一个价格$c_{i}$和品质$q_{i}$且每种数量无限.现在有$m$个人,第$i$个人有$v_{i}$元,每人每次会买他能买 ...

  6. BZOJ5063旅游——非旋转treap

    题目描述 小奇成功打开了大科学家的电脑. 大科学家打算前往n处景点旅游,他用一个序列来维护它们之间的顺序.初 始时,序列为1,2,...,n. 接着,大科学家进行m次操作来打乱顺序.每次操作有6步: ...

  7. BZOJ3223文艺平衡树——非旋转treap

    此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...

  8. BZOJ3224普通平衡树——非旋转treap

    题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...

  9. BZOJ3729Gty的游戏——阶梯博弈+巴什博弈+非旋转treap(平衡树动态维护dfs序)

    题目描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略.gt ...

随机推荐

  1. 关于DLL的创建与使用简单描述(C++、C#)

    前言 前一段时间在学关于DLL的创建与调用,结果发现网络上一大堆别人分享的经验都有点问题.现在整理分享一下自己的方法. 工具 Microsoft Visual Studio 2017 depends ...

  2. mongodb 复制(副本集)

    复制(副本集) 什么是复制 复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性,并可以保证数据的安全性 复制还允许从硬件故障和服务中断中恢复数据 为什么要复制 数据备份 数据灾 ...

  3. Scrum 冲刺 第四日

    目录 要求 项目链接 燃尽图 问题 今日任务 明日计划 成员贡献量 小组会议 要求 各个成员今日完成的任务(如果完成的任务为开发或测试任务,需给出对应的Github代码签入记录截图:如果完成的任务为调 ...

  4. 标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)

    标准C++类std::string的内存共享,值得体会: 详见大牛:https://www.douban.com/group/topic/19621165/ 顾名思义,内存共享,就是两个乃至更多的对象 ...

  5. 【iOS】Swift if let 和 if var

    if let unwrappedOptional = postDict { print("The optional has a value! It's \(unwrappedOptional ...

  6. 【iOS】字号问题

    一,ps和pt转换 px:相对长度单位.像素(Pixel).(PS字体) pt:绝对长度单位.点(Point).(iOS字体) 公式如下: pt=(px/96)*72. 二,字体间转换 1in = 2 ...

  7. ORM “杀器”之 JOOQ

    ORM “杀器”之 JOOQ IN 后端编程,JAVA,敏捷开发,数据库 JOOQ是啥? JOOQ 是基于Java访问关系型数据库的工具包,轻量,简单,并且足够灵活,可以轻松的使用Java面向对象语法 ...

  8. angular2 学习笔记 ( Rxjs, Promise, Async/Await 的区别 )

    Promise 是 ES 6 Async/Await 是 ES 7 Rxjs 是一个 js 库 在使用 angular 时,你会经常看见这 3 个东西. 它们都和异步编程有关,有些情况下你会觉得用它们 ...

  9. 开源软件:NoSql数据库 - 图数据库 Cassandra

    转载原文:http://www.cnblogs.com/loveis715/p/5299495.html Cassandra简介 在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了 ...

  10. Go语言的核心Routine-Channel

    前言 Go语言通过routine,提供了并发编程的支持. Routine特性 (1) goroutine是Go语言运行库的功能,不是操作系统提供的功能,goroutine不是用线程实现的. 例:启动一 ...