一 基本概念
线段树是一种基于分治思想的二叉树,它的每个节点对应一个[L,R]区间,叶子节点的区间 L=R。每个非叶子节点[L,R]的左孩子区间为[L,(L+R)/2],右孩子区间为[(L+R)/2,R]。[1,10] 区间的线段树如下。
二 线段树的存储方式
对于区间最值(最大值或最小值)查询问题,线段树的每个节点包含三个域:l、r、mx,其中 l 和 r 表示区间的左右端点,mx 表示[l,r]区间最值。
线段树除了最后一层,其他层构成一颗满二叉树,因此采用顺序存储方式,用一个数组 tree[] 存储节点。
以最大值为例,10 个元素 a[1..10]={5,3,7,2,12,1,6,4,8,15},线段树如下。
三 创建线段树
可以采用递归的方法创建线段树。
算法步骤:
1 若是叶子节点(l=r),则节点的最值就是对应位置的元素值。
2 若是非叶子节点,则递归创建左子树和右子树。
3 节点的区间最值等于该节点左右子树最值的最大值。
四 点更新
点更新指修改一个元素的值,例如将 a[i] 修改为 v。
算法步骤:
1 若是叶子节点,满足l=r 且 l=i,则修改该节点的最值为 v。
2 若是非叶子节点,则判断是在左子树中更新还是在右子树中更新。
3 返回时更新节点的最值。
例如,修改第 5 个节点的值为 14 ,先从树根向下找第5个元素所在的叶子节点,将其最值修改为 14,返回时更新路径上所有节点的最值(左右子节点最值的最大值)。
五 区间查询
区间查询指查询一个[l,r]区间的最值。
算法步骤:
1 若节点所在的区间被查询区间[l,r]覆盖,则返I可该节点的最值。
2 判断是在左子树中查询,还是在右子树中查询。
3 返回最值。
例如,在 [1,10] 的线段树中查询[3,5]区间的最值。