线段树---区间修改&乘法操作

首先是区间修改

直接暴力修改显然不优秀,我们使用一个lazy标记,标记当前加了多少

我们可以在修改时先存起来,在查询时再下传标记

类似于:

修改:lazy[x]+=k;

下传:lazy[x2]+=lazy[x],lazy[x2+1]+=lazy[x];

但是val数组一样需要更新,在修改时有没有什么优秀的方法能一次加完所有答案?

可以发现,实际上在修改时val[x]加上了区间长度个k,即:val[x]+=(rt-lt+1)*k

下传时同理:val[x2]+=(mid-lt+1)lazy[x],val[x2+1]+=(rt-mid+1-1)lazy[x];

最后,在下传时x的lazy需要清零,同时,只有lazy不为0时才会下传

可以得到:

void pushDown(int x,int lt,int rt){
	if(lazy[x]==0){
		return;
	}
	int mid=(lt+rt)/2;
	val[x*2]+=lazy[x]*(mid-lt+1);
	val[x*2+1]+=lazy[x]*(rt-mid);
	lazy[x*2]+=lazy[x];
	lazy[x*2+1]+=lazy[x];
	lazy[x]=0;
}
void update(int x,int lt,int rt,int ul,int ur,int k){
	if(lt>ur||rt<ul){
		return ;
	}
	if(lt>=ul&&rt<=ur){
		lazy[x]+=k;
		val[x]+=(rt-lt+1)*k;
		return ;
	}
	pushDown(x,lt,rt);
	int mid=(lt+rt)/2;
	update(x*2,lt,mid,ul,ur,k);
	update(x*2+1,mid+1,rt,ul,ur,k);
	pushUp(x);
}

然后是乘法操作

我们使用像加法一样的懒标记cheng[]来存储乘法的lazy标记,使用jia[]存储加法的(个人前世习惯)

首先,乘法一定会比加法先算,因为先加的话会影响乘法的答案,并且减起来不方便,如果我们先算乘法,并且在乘法修改时将加法的懒标记一起更新,类似于:

cheng[x]=k;
jia[x]
=k;

那么,在下传时同理:

cheng[x2]=cheng[x];
cheng[x2+1]=cheng[x];//乘法
jia[x2]=cheng[x];
jia[x2+1]=cheng[x];//加法同理
jia[x2]+=jia[x];
jia[x
2+1]+=jia[x];//加法下传

并且,乘法的初始值为1,不能一开始就乘0

就有了如下代码:

void pushDown(int x,int lt,int rt){
	if(jia[x]==0&&cheng[x]==1){
		return;
	}
	int mid=(lt+rt)/2;
	val[x*2]*=cheng[x];
	val[x*2+1]*=cheng[x];
	val[x*2]+=jia[x]*(mid-lt+1);
	val[x*2+1]+=jia[x]*(rt-mid);
	cheng[x*2]*=cheng[x];
	cheng[x*2+1]*=cheng[x];
	jia[x*2]*=cheng[x];
	jia[x*2+1]*=cheng[x];
	jia[x*2]+=jia[x];
	jia[x*2+1]+=jia[x];
	jia[x]=0;
	cheng[x]=1;
}
void upjia(int x,int lt,int rt,int ul,int ur,int k){
	if(lt>ur||rt<ul){
		return ;
	}
	if(lt>=ul&&rt<=ur){
		jia[x]+=k;
		val[x]+=(rt-lt+1)*k;
		return ;
	}
	pushDown(x,lt,rt);
	int mid=(lt+rt)/2;
	upjia(x*2,lt,mid,ul,ur,k);
	upjia(x*2+1,mid+1,rt,ul,ur,k);
	pushUp(x);
}
void upcheng(int x,int lt,int rt,int ul,int ur,int k){
	if(lt>ur||rt<ul){
		return ;
	}
	if(lt>=ul&&rt<=ur){
		cheng[x]*=k;
		jia[x]*=k;
		val[x]*=k;
		return ;
	}
	pushDown(x,lt,rt);
	int mid=(lt+rt)/2;
	upcheng(x*2,lt,mid,ul,ur,k);
	upcheng(x*2+1,mid+1,rt,ul,ur,k);
	pushUp(x);
}

同时,pushDown在update和query的时候都要下传,因为lazy数组会清零

两道模板就很简单了

线段树1
线段树2

posted @ 2025-08-23 20:16  KK_SpongeBob  阅读(21)  评论(0)    收藏  举报