线段树
基础与数据结构
说明
每个节点表示一个区间的聚合值;区间查询与单点更新为 O(log n)。
分析
叶节点存放原数组,内部节点保存左右子区间之和。查询半开区间 [l,r) 时,从两侧向上移动并累加被完整覆盖的节点。
示例补齐4片叶子为[2,3,5,0],查询[0,2)直接取左子树和5。查询将目标分为不重叠的完整区间;换成求最小值时单位元应为正无穷,不能照搬补零。
查看图表代码
适用前提与边界
构建需要 O(n) 时间与空间;示例展示区间和,单点更新可沿叶到根路径同步修改。 查询范围按原数组长度限定为0≤l≤r≤len(a);内部补齐槽不能当成真实元素,Sum(l,l)返回0。
示例输入与调用
go
tree := NewSegmentTree([]int{2, 3, 5})
fmt.Println(tree.Sum(0, 2))运行输出
text
5完整 Go 示例
go
package main
import "fmt"
type SegmentTree struct {
n int
tree []int
}
func NewSegmentTree(a []int) *SegmentTree {
n := 1
for n < len(a) {
n *= 2
}
t := &SegmentTree{n, make([]int, 2*n)}
copy(t.tree[n:], a)
for i := n - 1; i > 0; i-- {
t.tree[i] = t.tree[2*i] + t.tree[2*i+1]
}
return t
}
func (t *SegmentTree) Sum(l, r int) int {
l += t.n
r += t.n
s := 0
for l < r {
if l%2 == 1 {
s += t.tree[l]
l++
}
if r%2 == 1 {
r--
s += t.tree[r]
}
l /= 2
r /= 2
}
return s
}
func main() {
tree := NewSegmentTree([]int{2, 3, 5})
fmt.Println(tree.Sum(0, 2))
}继续阅读
- 系统学习
- 系统学习
- 系统学习