目录
什么是线段树?
线段树基本操作:
创建线段树
线段树单点更新
区间查询最大最小值
延迟标记(懒人标记)+pushdown操作
区间更新
求区间和
注:以下所有代码都是针对维护区间和的。
什么是线段树?
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
性质:对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。举个例子
- 创建一个线段树
线段树成员:
struct node
{
int val; //具体数值
int len; //覆盖区间长度
int lazy; //延迟标记
int l,r; //左右儿子编号
}tree[300005];
建树思想:递归建树,遇到叶子节点直接赋值,否则递归遍历左右建树,最后回溯即可。
void build(int root,int l,int r) //建树
{
int mid;
tree[root].l=l;tree[root].r=r;
tree[root].len=r-l+1;
if (l==r) tree[root].val=arr[l];
else
{
mid=(l+r)/2;
build(root*2,l,mid); //递归构造左子树
build(root*2+1,mid+1,r); //递归构造右子数
tree[root].val=tree[root*2].val+tree[root*2+1].val;//存储左右子树的和
}
}
- 单点更新线段树
递归更新,递归至要更新的叶子节点,回溯更改该叶子节点会导致其他节点的值
/*id: 待更新节点在原始数组arr中的下标
addVal: 更新的值(原来的值加上addVal)*/
void add(int root,int id,int addval) //单点更新
{
int mid;
if (tree[root].l==tree[root].r)
{
tree[root