标记永久化
第一次写线段树已经是一年多前的事情了,一年后把当初没有学懂的“标记永久化”重新学习了一下,好像也不是那么难了(/▽\)
1 标记永久化
标记永化化,顾名思义,指标记一旦被打上,就不再下传或清空。而是在询问的过程中计算每个遇到结点对当前询问的影响。
为了便于叙述,规范一下变量的意义:
\(add\) :表示这个区间的所有的数字共同加上的值。需要注意的是,区间的add值有一部分有祖先结点上,这一部分在递归过程中加以处理。
\(sum\) :表示这个区间除了\(add\)值外的和
下面这个等式可以检测你是否真正理解了上述变量的含义:
\[value\ of\ [l,r],id=sum[id]+(r-l+1)*(\sum_{from\ root\ to\ id}add)
\]
2 代码
ll query(int id,int l,int r,int x,int y){
if(x<=l&&r<=y) {return sum[id]+(r-l+1)*add[id];}
int mid=(l+r)>>1;
ll ans=(min(r,y)-max(l,x)+1)*add[id]; //计算当前结点对查询的贡献
if(x<=mid) ans+=query(id<<1,l,mid,x,y);
if(mid+1<=y) ans+=query(id<<1|1,mid+1,r,x,y);
return ans;
}
void modify(int id,int l,int r,int x,int y,ll k){
if(x<=l&&r<=y) {add[id]+=k; return;} //完全包含修改add
int mid=(l+r)>>1;
sum[id]+=(min(r,y)-max(l,x)+1)*k; // 不完全包含修改sum
if(x<=mid) modify(id<<1,l,mid,x,y,k);
if(mid+1<=y) modify(id<<1|1,mid+1,r,x,y,k);
}

浙公网安备 33010602011771号