Segment Tree - 线段树


线段树

给定个数字,求出这个区间上的所有数字之和

其中。该区间可以修改任意元素的值。

的时间复杂度内可以修改某个位置上的值,但需要的时间复杂度遍历数组累加求出区间上所有元素之和。而线段树的修改、求和的时间复杂度都为

线段树是一种二叉树,它将数组划分区间,线段树中的每个节点会有一个区间,表示数组上范围上被关注的内容,例如该区间上所有元素的和、最大/最小元素的值等。本问题关注区间上的元素之和。

节点代表数组上所有元素之和。左子树为上元素之和,右子树为上元素之和。线段树的叶子节点是长度为的区域。数组的线段树如图所示:

SegmentTree1.png

构造操作:从根节点开始,递归的将节点拆分为,则显然,即父节点的值等于左右孩子节点值的和,我们将区域上所有元素之和记录在线段树的节点上。像这样递归的分解左右孩子,直到叶子节点为止。构造操作的时间复杂度为

更新操作:修改区间中任意一个值需要修改从叶子节点到根节点这一分支上的所有节点,因为它们上所存储的信息都会受到影响。更新操作的时间复杂度为

查询操作:查询区间上所有元素之和,需要递归的从根节点向下匹配。对于节点有以下四种情况:

则该节点上的值即为所求,算法结束;

说明只属于其左孩子;

说明只属于其右孩子;

说明中一部分属于左孩子,另一部分属于右孩子,这时将拆分为两部分,分别匹配自己所属的区域;

实际编码时用数组来表示二叉树(也可以真的写一个二叉树),节点的左孩子为,右孩子为为二叉树根节点,代表区域上所有元素之和,左孩子表示区域之和,右孩子表示区域之和,以此类推。


源码

SegmentTree.h

SegmentTree.cpp

测试

SegmentTreeTest.cpp