平衡树(无旋treap)学习笔记
这里主要是讲无旋Treap,比较好维护,能实现大量功能,并且可持久化。
缺点在于常数大,码量大,并且时间复杂度期望为 \(\log n\),有极低概率成为大倒霉蛋。
什么是平衡树
平衡树是一种数据结构,这种数据结构是以二叉搜索树为主体,但是可以实现插入删除等操作。
平衡树比较常见的形式有 Splay,Treap,目前我只会Treap
Treap分为有旋和无旋,无旋Treap又称为FHQ-Treap,核心在于用堆+二叉搜索树树确定树的形态,单次操作期望时间复杂度为 \(\log n\) 的。
具体证明不会。
FHQ-Treap采用分裂+合并的方式来处理子树的问题,因此很多操作会比较快捷,比如查询某个数的排名,直接按照这个值分裂,取出小的那部分,记录树的大小即可。
平衡树内的值可以按照权值或者排名排序,左边的一般维护小的,右边一般维护大的。
怎么写平衡树
写平衡树首先有一个点就是要如何维护成一个堆,常见方法就是直接摇随机数,然后再合并是比较两个权值来确定谁在上面。
核心还是在于怎样实现分裂和合并操作
直接上代码
分裂:
pair<int,int> split(int p,int v){
if(!p)return {0,0};
if(val[p]<=v){
pair<int,int> tmp=split(rs[p],v);
rs[p]=tmp.first;
pushup(p);
return {p,tmp.second};
}
else {
pair<int,int> tmp=split(ls[p],v);
ls[p]=tmp.second;
pushup(p);
return {tmp.first,p};
}
}
合并:
int merge(int u,int v){
if(!u||!v)return u|v;
if(c[u]<c[v]){
rs[u]=merge(rs[u],v);
pushup(u);
return u;
}
else {
ls[v]=merge(u,ls[v]);
pushup(v);
return v;
}
}
平衡树也可以使用懒惰标记进行修改,也可以上传某个值,对左右子树内容与这个节点进行合并
这么说平衡树可以完成大部分线段树的内容,只是可以用线段树做的偏用平衡树,太有病了
反正这样其实差不多就水完了,毕竟数据结构,实现1的功能就那么点,重在理解
而我明显不想证明时间复杂度

浙公网安备 33010602011771号