这一部分感觉是最难的一部分了。
想要更新区间的值,可以通过一个for循环进行单点更新。。但是这样貌似比普通的遍历还慢。
所以,聪明的人们想到了一个好办法解决线段树不能解决区间更新的问题。通过一个懒惰标记来对已经更新的区间进行标记,然后计算出值,然后直接返回,不在更新子节点的值了。
当进行多次更新的时候,这时候就可以通过下推标记进行更新子节点。
代码如下:
下推懒惰标记:
//下推懒惰标记
int lazy[maxn<<2];
void Pushdown (int re,int ln,int rn) //ln 表示的是左子树的元素个数,rn表示的是右子树的元素个数
{
//如果有懒惰标记
if(lazy[re])
{
lazy[re<<1]+=lazy[re];
lazy[re<<1|1]+=lazy[re];
//求出两个子节点的值
tree[re<<1]+=lazy[re]*ln;
tree[re<<1|1]+=lazy[re]*rn;
//因为标记已经下传了,所以重新置0
lazy[re]=0;
}
}
区间更新:
//区间更新
void quee (int left,int right,int l,int r,int re,int data)// [left,right]表示要查询的区间,data表示区间更新的数值
{
if(l>=left&&r<=right)
{
//加上懒惰标记,并求出区间更新后的值
lazy[re]+=data;
tree[re]=data*(r-l+1);
return ;
}
int mid=(l+r)>>1;
//是否需要下推标记
Pushdown (re,mid-l+1,r-mid);
if(mid>=left)
quee (left,right,l,mid,re<<1,data);
if(mid<right)
quee (left,right,mid+1,r,re<<1|1,data);
pushup(re);
}