在线段树中会遇到区间更新的情况,例如 在区间求和问题中,令[a,b]区间内的值全部加c,若此时再采用单点更新的方法,就会耗费大量时间,这个时候就要用到懒标记来进行区间更新了。
设当前结点对应区间[l, r],待更新区间[a, b]
当 a ≤ l ≤ r ≤ b,即 [l, r]∈[a,b]时,不再向下更新,仅更新当前结点,并在该结点加上懒标记,当必须得更新/查询该结点的左右子 结点时,再利用懒标记的记录向下更新(pushdown)——懒标记也要向下传递,然后移除该结点的懒标记。
这样就不用每次都更新到叶子结点,减少了大量非必要操作,从而优化时间复杂度。
//建树
public static void build(int node,int l,int r){
if(l==r){
tree[node]=arr[r];
}
else{
int mid=(l+r)/2;
int left_node=2*node+1;
int right_node=2*node+2;
build(left_node,l,mid);
build(right_node,mid+1,r);
tree[node]=tree[left_node]+tree[right_node];
}
}
//向下更新
public static void pushdown(int node,int l,int r){
if(lazy[node]==0){
return;
}
else{
int mid=(l+r)/2;
int left_node=2*node+1;
int right_node=2*node+2;
tree[left_node]+=lazy[node]*(mid-l+1);
lazy[left_node]+=lazy[node];
tree[right_node]+=lazy[node]*(r-mid);
lazy[right_node]+=lazy[node];
lazy[node]=0;
}
}
//区间更新
public static void update(int node,int l,int r,int a,int b,long c){
if(l>=a&&r<=b){
tree[node]+=(r-l+1)*c;
lazy[node]+=c;
return;
}
pushdown(node,l,r);
int mid=(l+r)/2;
int left_node=2*node+1;
int right_node=2*node+2;
if(b<=mid){
update(left_node,l,mid,a,b,c);
}
else if(a>mid){
update(right_node,mid+1,r,a,b,c);
}
else{
update(left_node,l,mid,a,b,c);
update(right_node,mid+1,r,a,b,c);
}
tree[node]=tree[left_node]+tree[right_node];
}
//区间查询
public static long query(int node,int l,int r,int a,int b){
if(l>=a&&r<=b){
return tree[node];
}
pushdown(node,l,r);
int mid=(l+r)/2;
int left_node=2*node+1;
int right_node=2*node+2;
if(b<=mid) return query(left_node,l,mid,a,b);
else if(a>mid) return query(right_node,mid+1,r,a,b);
else return query(left_node,l,mid,a,b)+query(right_node,mid+1,r,a,b);
}
例题链接:https://vjudge.net/contest/336099#problem/A
题解:https://blog.csdn.net/daoshen1314/article/details/102798414