无旋Treap

本文介绍了无旋Treap的基本概念及实现方式,包括拆分子树和合并子树的过程,提供了具体的代码示例,并讨论了如何进行点修改以及区间操作。

    想要搞带区间的平衡树,要么用splay,要么用无旋treap。(现在只会后面的)

    先%一下大佬LadyLex

    无旋treap简言之不再有左旋和右旋,而多了拆分子树和合并子树的过程。

    slipt为拆树。D 为定义的pair,first是拆下来的树,second是拆下来后剩下的原树。

    如果要拆下来的树的大小比左子树小,就拆左子树,并把拆完的树接回来。

    如果左子树不够大,就要连上根和右子树,把拆下来的树接在原树上->要拆的树,剩下的树就是“拆剩下的原树”

D split(treap *f,int k)
{
	if(f==null)return  D(null,null);
	push(f);D y;
	if(f->ch[0]->size>=k)
	    {y=split(f->ch[0],k);f->ch[0]=y.second;f->update();y.second=f;}
	else
	    {y=split(f->ch[1],k-f->ch[0]->size-1);f->ch[1]=y.first;f->update();y.first=f;}    
	return y;
}
      merge为合并树。因为维护的树根节点的id值最小(我这么维护的)a树的值要比b树的小。

     如果a的id小,把b接为a的右子树,反之,把a接为b的左子树。

treap* merge(treap *a,treap *b)
{
	if(a==null)return b;
	if(b==null)return a;
	push(a);push(b);
	if(a->id<b->id)
	     {a->ch[1]=merge(a->ch[1],b);a->update();return a;}
	else
	     {b->ch[0]=merge(a,b->ch[0]);b->update();return b;}
}

     这个只是点的修改,如果为区间,加一个类似线段树的延迟标记,记录当前节点是否更改。

     插入值

inline void Insert(int v)
 {
     int k=Getkth(root,v);
     D x=Split(root,k);
     Treap *o=new Treap(v);
     root=Merge(Merge(x.first,o),x.second);
 }
      删除值

void Delete(int v)
 {
     int k=Getkth(root,v);
     D x=Split(root,k);
     D y=Split(x.second,1);
     root=Merge(x.first,y.second);
 }
    获得此点的排名

int Getkth(Treap *o,int v)
 {
     if(o==NULL)return 0;
     return(o->val>=v)?Getkth(o->ch[0],v):Getkth(o->ch[1],v)+size(o->ch[0])+1;
 }

       求某点的权值

inline int get_val(int rank)
{
	D x=split(root,rank-1);
	D y=split(x.second,1);
	int ans=y.first->h;
	root=merge(merge(x.first,y.first),y.second);
	return ans;
}

    我说的并不是太明白,链接一下LadyLex的完美讲解

08-01
Treap(Tree + Heap)是一种结合了二叉搜索树(BST)和堆(Heap)特性的平衡二叉搜索树数据结构。其核心原理在于每个节点维护两个值:一个用于二叉搜索树性质的键值(key),以及一个用于最大堆性质的优先级(priority)。通过这两个属性,Treap在插入和删除操作时保持树的平衡性,从而确保操作的时间复杂度接近于对数级别。 ### Treap的基本原理 1. **二叉搜索树性质**:对于任意节点,其左子树中所有节点的键值小于当前节点的键值,右子树中所有节点的键值大于当前节点的键值。 2. **堆性质**:每个节点的优先级大于其子节点的优先级,这样可以确保树的结构在插入或删除时通过转操作保持平衡。 在插入新节点时,Treap首先按照二叉搜索树的方式找到合适的位置,并赋予该节点一个随机的优先级。如果该节点的优先级违反了堆性质,则通过转操作调整树的结构以恢复堆性质。删除操作类似,通过转确保堆性质得以维持。 ### 无Treap的实现 无Treap(Non-Rotating Treap)是Treap的一个变种,它通过分裂(Split)和合并(Merge)操作来实现树的平衡,而不是传统的转操作。分裂操作将树按照某个键值或位置分割为两部分,而合并操作将两个树合并为一个。这种方式简化了实现逻辑,尤其是在处理复杂操作时[^2]。 例如,分裂操作可以通过以下方式实现(以键值为分割点): ```python def split(node, key): if node is None: return (None, None) if node.key <= key: left, right = split(node.right, key) node.right = left return (node, right) else: left, right = split(node.left, key) node.left = right return (left, node) ``` 合并操作则需要确保堆性质的维护: ```python def merge(left, right): if left is None: return right if right is None: return left if left.priority > right.priority: left.right = merge(left.right, right) return left else: right.left = merge(left, right.left) return right ``` ### 应用场景 Treap由于其高效的平衡特性,广泛应用于需要高效查找、插入和删除操作的场景。常见的应用包括: - **数据库索引**:Treap可以用于实现高效的索引结构,支持快速的数据检索。 - **内存中的集合与映射**:在需要频繁插入和删除元素的场景中,Treap提供了良好的性能保障。 - **算法竞赛**:在某些需要高效数据结构的竞赛题中,Treap常被用来实现动态集合操作[^1]。 ### 实现细节 在实现Treap时,需要注意以下几点: - **随机优先级生成**:为了保证树的平衡性,每个节点的优先级应随机生成,通常使用大范围的整数以减少冲突的可能性。 - **递归与非递归实现**:虽然递归实现较为直观,但在大规模数据处理时可能会导致栈溢出,因此在实际应用中可以考虑非递归实现。 - **类型安全与内存管理**:特别是在使用Rust等语言时,需注意类型约束和内存安全,以确保程序的稳定性和可靠性[^1]。 通过理解Treap的原理和实现方式,开发者可以更好地将其应用于实际项目中,并根据需求进行扩展和优化。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值