标记永久化

第一次写线段树已经是一年多前的事情了,一年后把当初没有学懂的“标记永久化”重新学习了一下,好像也不是那么难了(/▽\)

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);
}
posted @ 2020-06-29 21:54  ticmis  阅读(1012)  评论(0)    收藏  举报