非旋转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. ios swift例子源码网址总结

    http://blog.csdn.net/woaifen3344/article/details/40079351 http://www.ruanman.net/swift/learn/4607.ht ...

  2. bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候

    http://www.lydsy.com/JudgeOnline/problem.php?id=4869 欧拉降幂+线段树,每个数最多降log次,模数就会降为1 #include<cmath&g ...

  3. service层报错找不到方法Invalid bound statement (not found)

    报错信息如下 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.imooc.se ...

  4. win10 系统右键菜单不显示文字(只有小图标)修复方法

    如下图,win10点击鼠标右键调出菜单时,看不到菜单的文字,只显示了小图标. 解决方法: Cortana 搜索 cmd ,看到 命令提示符,右键,选择 以管理员身份运行. 在命令提示符里输入以下命令, ...

  5. JAVA_SE基础——51.内部类

    在Java中,允许在一个类的内部定义类,这样的类称作内部类,这个内部类所在的类称作外部类.根据内部类的位置.修饰符和定义的方式可分为成员内部类.静态内部类.方法(局部内部类)内部类. 内部类:一个类定 ...

  6. linux下面的打包压缩命令

    tar命令 tar [-cxtzjvfpPN] 文件与目录 ....linux下面压缩之前要把一堆文件打个包再压缩,即使只有一个文件也需要打个包.例子:tar czvf 1.tar.gz hello. ...

  7. LeetCode & Q13-Roman to Integer-Easy

    Math String Description: Given a roman numeral, convert it to an integer. Input is guaranteed to be ...

  8. 第五章 JavaScript对象及初识面向对象

    第五章   JavaScript对象及初识面向对象 一.对象 在JavaScript中,所有事物都是对象,如字符串.数值.数组.函数等. 在JavaScript对象分为内置对象和自定义对象,要处理一些 ...

  9. $.ajax 中的contentType

    $.ajax 中的contentType 在 cnodejs.org 论坛中有一个问题,让我也很奇怪,说是 $.ajax 设置数据类型 applicaiton/json之后,服务器端(express) ...

  10. Python内置函数(15)——memoryview

    英文文档: class memoryview(obj) memoryview objects allow Python code to access the internal data of an o ...