平衡树(二叉树)

线段树不支持插入or删除一个数于是平衡树产生了

常见平衡树:treap(比sbt慢,好写吧),SBT(快,比较好写,有些功能不支持),splay(特别慢,复杂度当做根号n来用,功能强大,不好写),rbt(红黑树,特别快),//替罪羊树,朝鲜树

晚上要讲的不旋转平衡树:

平衡树:

节点的左儿子中的每一个一定比他小,右儿子中的每一个一定比他大

那么它的中序遍历是有序的

用下标建树,那么区间询问的话就是求一棵子数和子树根和领一棵子数的一部分

treap:

tree+heap,平衡树和heap的性质是矛盾的,所以每个节点存一个key和value

key值满足heap性质,value满足平衡树的性质,这样的树叫做treap?

插入:

插入的新节点的key值随机,调用rand函数(这样保证树的深度一定是logn的)改变树的形态使它重新满足hea与平衡树性质

操作1.merge:

merge(P1,P2):把以p1为根的treap和以p2为根的treap合并成一个treap(p1中的所有制小于

操作2.split:

把以p为根的treap中拿出k小的数,组成一个新treap

保证原先树中的所有数>新树中所有数

可持久化treap :

插:

建一个只有一个点的树(要插得数)例如(2.33)把(1,2)splay出来,再把新树(2.33)和(1,2)merge起来,再把(1,2,2.33)和(4,5)merge 一下

删除一个:

如删除(2.33),先把split(treap,3),此时把splay把(1,2)与(2.33,4,5)分离在split(treep2,1),此时(2.33)与(4,5)分离

在merge(treap1,treap3)合并即把(1,2),(4,5)合并,那么2.33就没了

实际操作

merge时,找key值最大的作为新treap的根,不是p1就是p2

1要是p1.p>=p2.p此时p1作为新根,那么p1的左儿子不会变换,右子树就是p1的右子树和p2 merge 一下,即 merge(p1.r,p2);

2要是p2.p>p1.p此时p2作为新根,那么p2的右儿子不会变换,左儿子就是p2的

左子树 和 p1 mege 一下 即 merge(p2.l,p1);

split(p,k)几点记录value,key,l,r,size

p.L<-p->p.r;

1.要是k<=p.l.size 说明k小的点全在左子数,递归split(p.l,k);构成新树的时候直接把split后剩下的左子树接到P根上就好了

2.k=p.l.size+1;,返回两棵树(p.l-p,p.r)

3.k>p.l.siz+1,左边已经全不要,那么就split(p.r,k-p.l.size-1);

返回两棵树(p.l-p-p.r,剩余p.r)

merge:

int merge(int x,int y) {
if(!x) return y;//left son is empty
else if(!y)return x;//right son is empty
if(key[x]<key[y]) {
tree[x][1]=merge(tree[x][1],y);//union y_tree to x's right son
update(x);
return x;
}
else {
tree[y][0]=merge(x,tree[y][0]);//union x_tree to y'left son
update(y);
return y;
}
}

split:

void split(int now,int k,int &x,int &y) {//根据插入数的val值,把树分为小于等于k的,和大于k的
if (!now) x=y=0;//指针为空
else {
if (val[now]<=k)
x=now,split(tree[now][1],k,tree[now][1],y);//分割标准大于当前节点val访问右子树
else
y=now,split(tree[now][0],k,x,tree[now][0]);//否则访问左子树
update(now);
}
}

query_min:

查询那些数比x数小,当找到一个根节点比x小时,那么该节点的所有子树都比他小,那么就把子树size+1加到答案里-->删除一个数的时候时用来确定split的k(比要删除的数小的)值

query_kth

查询第k大的数

int kth(int now,int k) {
while(1) {
if (k<=siz[tree[now][0]])//左子树大小比k大说明第k大在左子树中
now=tree[now][0];
else
if (k==siz[tree[now][0]]+1)
return now;
else
k-=siz[tree[now][0]]+1,now=tree[now][1];//在右子树中查询第k-左子树子树个数 大的数
}
}

查询数a的rank

按照权值进行split,split出的x数(所有节点权值小于a)的大小+1,就是a的rank

split(root,a-1,x,y);
printf("%d\n",siz[x]+1);
root=merge(x,y);

插入一个新节点

int make_new(int v) {
siz[++sz]=1;
val[sz]=v;
key[sz]=rand();
return sz;
}

delite a number

删除一个数,把这个数split出来,然后将另外两颗split出来的树merge起来

            split(root,a,x,z);
split(x,a-1,x,y);
y=merge(tree[y][0],tree[y][1]);
root=merge(merge(x,y),z);

查询前驱

查询a的前驱

查询按照a作为标准split出的x子树中的最大值

split(root,a-1,x,y);
printf("%d\n",val[kth(x,siz[x])]);
root=merge(x,y);

后继

查询a的后继

查询按照a作为标准split出的y子树中的最小值

            split(root,a,x,y);
printf("%d\n",val[kth(y,1)]);
root=merge(x,y);

区间操作

总结,利用split与merge完成各种操作

平衡树之非旋Treap的更多相关文章

  1. [模板] 平衡树: Splay, 非旋Treap, 替罪羊树

    简介 二叉搜索树, 可以维护一个集合/序列, 同时维护节点的 \(size\), 因此可以支持 insert(v), delete(v), kth(p,k), rank(v)等操作. 另外, prev ...

  2. 2018.08.05 bzoj3223: Tyvj 1729 文艺平衡树(非旋treap)

    传送门 经典的平衡树问题,之前已经用splay写过一次了,今天我突发奇想,写了一发非旋treap的版本,发现挺好写的(虽然跑不过splay). 代码: #include<bits/stdc++. ...

  3. bzoj 3224: Tyvj 1728 普通平衡树【非旋treap】

    就是非旋treap的板子 #include<iostream> #include<cstdio> #include<cstdlib> using namespace ...

  4. 平衡树简单教程及模板(splay, 替罪羊树, 非旋treap)

    原文链接https://www.cnblogs.com/zhouzhendong/p/Balanced-Binary-Tree.html 注意是简单教程,不是入门教程. splay 1. 旋转: 假设 ...

  5. 非旋 treap 结构体数组版(无指针)详解,有图有真相

    非旋  $treap$ (FHQ treap)的简单入门 前置技能 建议在掌握普通 treap 以及 左偏堆(也就是可并堆)食用本blog 原理 以随机数维护平衡,使树高期望为logn级别, FHQ  ...

  6. 2827: 千山鸟飞绝 非旋treap

    国际惯例的题面:看起来很不可做的样子,我们先来整理一下题意吧.就是,维护每个点曾经拥有过的最大的两个属性值,支持把点的位置移动.我们用map对每个位置进行离散化,对每个位置建立一个平衡树.为了方便分离 ...

  7. 2018.08.06 bzoj1500: [NOI2005]维修数列(非旋treap)

    传送门 平衡树好题. 我仍然是用的fhqtreap,感觉速度还行. 维护也比线段树splay什么的写起来简单. %%%非旋treap大法好. 代码: #include<bits/stdc++.h ...

  8. 2018.07.24 loj#107. 维护全序集(非旋treap)

    传送门 就是普通平衡树,可以拿来练非旋treap" role="presentation" style="position: relative;"&g ...

  9. 2018.07.06 BZOJ 1588: HNOI2002营业额统计(非旋treap)

    1588: [HNOI2002]营业额统计 Time Limit: 5 Sec Memory Limit: 162 MB Description 营业额统计 Tiger最近被公司升任为营业部经理,他上 ...

随机推荐

  1. HashTable, HashMap,TreeMap区别

    java为数据结构中的映射定义了一个接口java.util.Map,而HashMap Hashtable和TreeMap就是它的实现类.Map是将键映射到值的对象,一个映射不能包含重复的键:每个键最多 ...

  2. Jconsole连接Tomcat JVM

    修改java虚拟机启动参数 在%TOMCAT_HOME%\bin\catalina.sh文件的最顶端 JAVA_OPTS=”-Dcom.sun.management.jmxremote.port=10 ...

  3. hadoop伪分布式集群的搭建

    集群配置: jdk1.8.0_161 hadoop-2.6.1 linux系统环境:Centos6.5 创建普通用户  dummy 设置静态IP地址 Hadoop伪分布式集群搭建: 为普通用户添加su ...

  4. Windows API 学习记录1

    这里面的好多函数不能死记硬背,知道有这个函数就行,等用到了,再回来细看 一.窗口管理函数包括以下几类: 按钮函数(Button) Microsoft提供了对话框和控制来支持应用程序与用户之间的交互通讯 ...

  5. MOCTF 简单注入

    最近在练习sql注入写脚本,记录一下思路,刚学的and 1=1也拿出来溜溜 http://119.23.73.3:5004/?id=1 首先,没有被过滤是正常显示. 没有被过滤但是查询不到就是空白,比 ...

  6. Cannot set property 'innerHTML' of null 问题的解决

    错误第一次写web 前端代码,出现了“Cannot set property ‘innerHTML’ of null”的错误代码,然后不知道原因在哪? 解决方案在网上查了下资料,原来是js 代码从上往 ...

  7. Leetcode 546.移除盒子

    移除盒子 给出一些不同颜色的盒子,盒子的颜色由数字表示,即不同的数字表示不同的颜色.你将经过若干轮操作去去掉盒子,直到所有的盒子都去掉为止.每一轮你可以移除具有相同颜色的连续 k 个盒子(k > ...

  8. 关于eclipse连接mysql jar包

    步骤如下: 右键工程--选择build path -- add  Libraries. 弹出框选user library,点击next. 弹出框点击add libraries . 继续点击new ,输 ...

  9. ansible中playbook使用

    palybook使用 ####yaml语法ansible中使用的yaml基础元素:变量Inventory条件测试迭代 playbook的组成结构InventoryModulesAd Hoc Comma ...

  10. Vue - methods 方法

    一.methods中参数的传递 使用方法和正常的javascript传递参数的方法一样,分为两部: 1.在methods的方法中进行声明,比如我们给add方法加上一个num参数,就要写出add:fun ...