codeforces-go中的平衡树:Treap实现细节
Treap(树堆)是一种结合了二叉搜索树(BST)和堆(Heap)特性的数据结构,通过随机化优先级维护树的平衡。在codeforces-go项目中,Treap的实现位于copypasta/treap.go,其核心设计融合了BST的有序性与堆的堆序性,确保操作复杂度为O(log n)。
数据结构定义
Treap节点结构包含左右子树指针、优先级、子树大小及键值对信息:
type tpNode struct {
lr [2]*tpNode // 左右子树,0表示左,1表示右
priority uint // 最大堆优先级
sz int // 子树大小
msz int // 多集大小(含重复元素计数)
key tpKeyType // 键
val tpValueType // 值(用于多集计数)
}
节点优先级通过随机数生成,确保树结构在概率意义上平衡。子树大小维护通过maintain方法实现:
func (o *tpNode) maintain() {
o.sz = 1 + o.lr[0].size() + o.lr[1].size()
o.msz = int(o.val) + o.lr[0].mSize() + o.lr[1].mSize()
}
核心操作实现
旋转操作
旋转是维持Treap平衡的关键,分为左旋和右旋:
// d=0:左旋,返回o的右儿子;d=1:右旋,返回o的左儿子
func (o *tpNode) rotate(d int) *tpNode {
x := o.lr[d^1]
o.lr[d^1] = x.lr[d]
x.lr[d] = o
o.maintain()
x.maintain()
return x
}
左旋将右子树提升为新根,右旋将左子树提升为新根,旋转后需重新维护子树大小。
插入操作
插入流程遵循BST规则,插入后通过旋转调整以满足堆优先级:
func (t *treap) _put(o *tpNode, key tpKeyType, val tpValueType) *tpNode {
if o == nil {
return &tpNode{priority: t.fastRand(), sz: 1, msz: 1, key: key, val: val}
}
if d := o.cmp(key); d >= 0 { // 0:左子树,1:右子树
o.lr[d] = t._put(o.lr[d], key, val)
if o.lr[d].priority > o.priority { // 子节点优先级更高,触发旋转
o = o.rotate(d ^ 1) // 左子树右旋(d=0→d^1=1),右子树左旋(d=1→d^1=0)
}
} else {
o.val += val // 键已存在,更新值(支持重复元素)
}
o.maintain()
return o
}
删除操作
删除通过将目标节点旋转至叶节点后移除,过程中始终保持堆优先级:
func (t *treap) _delete(o *tpNode, key tpKeyType) *tpNode {
if o == nil {
return nil
}
if d := o.cmp(key); d >= 0 {
o.lr[d] = t._delete(o.lr[d], key)
} else {
if o.val > 1 { // 多集删除,减少计数
o.val--
} else { // 叶节点删除
if o.lr[1] == nil {
return o.lr[0]
}
if o.lr[0] == nil {
return o.lr[1]
}
// 选择优先级高的子树旋转至根
d = 0
if o.lr[0].priority > o.lr[1].priority {
d = 1
}
o = o.rotate(d)
o.lr[d] = t._delete(o.lr[d], key)
}
}
o.maintain()
return o
}
与笛卡尔树的关联
Treap本质上属于笛卡尔树(Cartesian Tree)的一种变体,笛卡尔树的实现可见copypasta/cartesian_tree.go。两者均通过键值与优先级(或权值)构建树结构,但Treap的优先级为随机生成,而笛卡尔树通常基于数组元素值。
可视化功能
Treap提供树形打印功能,以逆时针90°方向展示结构:
func (t *treap) String() string {
if t.root == nil {
return "Empty\n"
}
treeSB := &strings.Builder{}
treeSB.WriteString("Root\n")
t.root.draw(treeSB, &strings.Builder{}, true)
return treeSB.String()
}
示例输出:
Root
└── 62[sz:...,msz:...
├── 90[sz:...,msz:...
│ ├── 66[sz:...,msz:...
│ │ └── 74[sz:...,msz:...
│ └── 94[sz:...,msz:...
└── 40[sz:...,msz:...
└── 25[sz:...,msz:...
泛型版本与扩展
代码中包含泛型占位实现(treapM),支持自定义比较器:
type treapM[K comparable, V any] struct {
rd uint
root *nodeM[K, V]
comparator func(a, b K) int // 自定义比较器
}
完整泛型实现可参考copypasta/treap/目录,支持有序映射、集合等扩展功能。
应用场景
Treap适用于需要高效插入、删除和查询的数据场景,如:
- 动态有序序列维护
- 区间查询与排名统计
- 离线算法中的数据结构支撑
项目中相关题目参考:
- 洛谷P3369 平衡树模板题
- AtCoder ABC245E 离线查询+Treap应用
通过结合BST与堆的特性,Treap在codeforces-go中提供了可靠的平衡树实现,为算法竞赛中的复杂数据处理需求提供高效支持。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



