雁过留声 发表于 4 天前

Go实现动态开点线段树

1、线段树介绍

线段树是一种用于高效处理区间查询和区间更新的数据结构,当我们需要解决一个频仍更新区间值的问题的时间,就可以采用线段树的结构进行解决。线段树的核心思想是将区间分为多个子区间进行管理,越往下区间范围越小,根节点表示整个线段树能表示的区间。
本文记载使用Go实现动态开点线段树的方式,该模板的线段树用于解决区间求和问题,另有求解区间最小值、最大值的线段树可以进行微调修改即可。
区间查询、区间更新的时间复杂度均为O(logN)。
2、动态开点线段树实现

动态开点的核心在于,需要缩小范围,即进入子节点的时间再进行创建,相对于使用数组来实现线段树,可以更大的减小空间开销。
1、线段树节点

一个节点需要记载它的左子节点、右子节点、当前节点表示的区间的和val,以及暂未下推给子节点的懒惰值lazy。
type SegTreeNode struct {
        lazyint
        val   int
        left*SegTreeNode
        right *SegTreeNode
}2、线段树的创建

整个线段树只需要记载一个根节点以及该线段树表示的区间上届。
type SegTree struct {
        //线段树的范围,0~N
        N    int
        root *SegTreeNode
}

// 创建线段树
func CreateSegTree(n int) *SegTree {
        return &SegTree{
                N: n,
                root: &SegTreeNode{
                        lazy:0,
                        val:   0,
                        left:nil,
                        right: nil,
                },
        }
}3、递归上推

当更新完了子节点后,回到当前节点的时间,需要更新当前节点的值,表示从树的底部上推值。
// 递归上推
func (ST *SegTree) Pushup(node *SegTreeNode) {
        node.val = node.left.val + node.right.val
}4、懒惰下推

当需要缩小查找区间的时间,需要向下查找,这时间要先把懒惰值下推,防止查找出错误的结果,也防止子节点还未创建。
// 同步下推
func (ST *SegTree) Pushdown(node *SegTreeNode, leftnum, rightnum int) {
        //创建左右节点
        if node.left == nil {
                node.left = new(SegTreeNode)
        }
        if node.right == nil {
                node.right = new(SegTreeNode)
        }
        //下推节点懒惰标记
        if node.lazy == 0 {
                return
        }
        node.left.val += leftnum * node.lazy
        node.right.val += rightnum * node.lazy
        //下推
        node.left.lazy += node.lazy
        node.right.lazy += node.lazy
        //置零
        node.lazy = 0
}起首先创建左右节点,如果没有需要下推的懒惰标记则直接返回。否则就更新左右节点的val和lazy。
5、更新操作

// 更新操作,更新区间的值,start和end是当前处在区间func (ST *SegTree) Update(node *SegTreeNode, start, end, left, right, val int) {        if left
页: [1]
查看完整版本: Go实现动态开点线段树