多标记线段树处理法(洛谷3373,codevs4927)

1.洛谷P3373线段树2

加法和乘法标记,处理方法:

加法时直接添加标记,乘法时将加法标记也进行修改,在标记下放时,先放乘法(直接乘),再放加法(直接加),放乘法标记时要同时修改加法标记。

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
ll read(){
	ll w=1,q=0;char ch=' ';
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')q=(ll)q*10+ch-'0',ch=getchar();
	return (ll)w*q;
}
int n,m;
ll mod;
ll a[100005],sum[400005],mul[400005],laz[400005];
void up(int i){sum[i]=(sum[(i<<1)]+sum[(i<<1)|1])%mod;}
void pd(int i,int s,int t){
	int l=(i<<1),r=(i<<1)|1,mid=(s+t)>>1;
	if(mul[i]!=1){
	mul[l]*=mul[i];mul[l]%=mod;mul[r]*=mul[i];mul[r]%=mod;
	laz[l]*=mul[i];laz[l]%=mod;laz[r]*=mul[i];laz[r]%=mod;
	sum[l]*=mul[i];sum[l]%=mod;sum[r]*=mul[i];sum[r]%=mod;
	mul[i]=1;
	}
	if(laz[i]){
	sum[l]+=laz[i]*(mid-s+1);sum[l]%=mod;
	sum[r]+=laz[i]*(t-mid);sum[r]%=mod;
	laz[l]+=laz[i];laz[l]%=mod;
	laz[r]+=laz[i];laz[r]%=mod;
	laz[i]=0;
	}return;
}
void build(int s,int t,int i){
	mul[i]=1;if(s==t){sum[i]=a[s];return;}
	int mid=(s+t)>>1;
	build(s,mid,i<<1);build(mid+1,t,(i<<1)|1);up(i);
}
void chen(int l,int r,int s,int t,int i,ll z){
	int mid=(s+t)>>1;
	if(l<=s&&t<=r){
		mul[i]*=z;mul[i]%=mod;laz[i]*=z;laz[i]%=mod;
		sum[i]*=z;sum[i]%=mod;return;
	}
	pd(i,s,t);
	if(mid>=l)chen(l,r,s,mid,(i<<1),z);
	if(mid+1<=r)chen(l,r,mid+1,t,(i<<1)|1,z);
	up(i);
}
void add(int l,int r,int s,int t,int i,ll z){
	int mid=(s+t)>>1;
	if(l<=s&&t<=r){
		sum[i]+=z*(t-s+1);sum[i]%=mod;laz[i]+=z;laz[i]%=mod;
		return;
	}
	pd(i,s,t);
	if(mid>=l)add(l,r,s,mid,(i<<1),z);
	if(mid+1<=r)add(l,r,mid+1,t,(i<<1)|1,z);
	up(i);
}
ll getans(int l,int r,int s,int t,int i){
	int mid=(s+t)>>1;ll tot=0;
	if(l<=s&&t<=r){return sum[i];}
	pd(i,s,t);
	if(mid>=l)tot+=getans(l,r,s,mid,(i<<1));
	tot%=mod;
	if(mid+1<=r)tot+=getans(l,r,mid+1,t,(i<<1)|1);
	return tot%mod;
}
int main()
{
	int i,j,x,y,bh;
	ll z;
	n=read();m=read();mod=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,n,1);
	for(i=1;i<=m;i++){
		bh=read();
		if(bh==1){
			x=read();y=read();z=read();
			chen(x,y,1,n,1,z);
		}
		else if(bh==2){
			x=read();y=read();z=read();
			add(x,y,1,n,1,z);
		}
		else if(bh==3){
			x=read();y=read();
			printf("%lld\n",getans(x,y,1,n,1));
		}
	}
   	return 0;
} 

2.codevs4927线段树练习5

加法标记和区间赋值标记,修改区间赋值标记时将加法标记变成0,修改加法标记时直接改。下放时先放区间赋值标记,同时把儿子的加法标记变为0,再下放加法标记。

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
const int SN=400005;
ll read(){
	char ch=' ';ll w=1,q=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')q=(ll)q*10+ch-'0',ch=getchar();
	return (ll)w*q;
}
int n,m;
ll a[100005],sum[SN],maxx[SN],minn[SN],se[SN],laz[SN];
void up(int i){
	int l=(i<<1),r=(i<<1)|1;
	sum[i]=sum[l]+sum[r];
	maxx[i]=max(maxx[l],maxx[r]);
	minn[i]=min(minn[l],minn[r]);
}
void pd(int i,int s,int t){
	int l=(i<<1),r=(i<<1)|1,mid=(s+t)>>1;
	if(se[i]>=0){//如果有add标记,说明是set后面的
		sum[l]=(ll)(mid-s+1)*se[i];sum[r]=(ll)(t-mid)*se[i];
		maxx[l]=se[i];maxx[r]=se[i];
		minn[l]=se[i];minn[r]=se[i];
		laz[l]=0;laz[r]=0;se[l]=se[i];se[r]=se[i];
		se[i]=-1;
	}
	if(laz[i]){
		sum[l]+=(ll)(mid-s+1)*laz[i];sum[r]+=(ll)(t-mid)*laz[i];
		maxx[l]+=laz[i];maxx[r]+=laz[i];
		minn[l]+=laz[i];minn[r]+=laz[i];
		laz[l]+=laz[i];laz[r]+=laz[i];laz[i]=0;
	}
}
void build(int s,int t,int i){
	se[i]=-1;if(s==t){sum[i]=maxx[i]=minn[i]=a[s];return;}
	int mid=(s+t)>>1;
	build(s,mid,(i<<1));build(mid+1,t,(i<<1)|1);up(i);
}
void add(int l,int r,int s,int t,int i,ll z){
	if(l<=s&&t<=r){
		sum[i]+=(ll)z*(t-s+1);maxx[i]+=z;minn[i]+=z;
		laz[i]+=z;return;
	}
	pd(i,s,t);int mid=(s+t)>>1;
	if(mid>=l)add(l,r,s,mid,(i<<1),z);
	if(mid+1<=r)add(l,r,mid+1,t,(i<<1)|1,z);up(i);
}
void chan(int l,int r,int s,int t,int i,ll z){
	if(l<=s&&t<=r){
		sum[i]=(ll)z*(t-s+1);maxx[i]=z;minn[i]=z;
		laz[i]=0;se[i]=z;return;
	}
	pd(i,s,t);int mid=(s+t)>>1;
	if(mid>=l)chan(l,r,s,mid,(i<<1),z);
	if(mid+1<=r)chan(l,r,mid+1,t,(i<<1)|1,z);up(i);
}
ll getsum(int l,int r,int s,int t,int i){
	if(l<=s&&t<=r)return sum[i];
	pd(i,s,t);int mid=(s+t)>>1;ll tot=0;
	if(mid>=l)tot+=getsum(l,r,s,mid,(i<<1));
	if(mid+1<=r)tot+=getsum(l,r,mid+1,t,(i<<1)|1);
	return tot;
}
ll getmin(int l,int r,int s,int t,int i){
	if(l<=s&&t<=r)return minn[i];
	pd(i,s,t);int mid=(s+t)>>1;ll tot=LLONG_MAX;
	if(mid>=l)tot=getmin(l,r,s,mid,(i<<1));
	if(mid+1<=r)tot=min(tot,getmin(l,r,mid+1,t,(i<<1)|1));
	return tot;
}
ll getmax(int l,int r,int s,int t,int i){
	if(l<=s&&t<=r)return maxx[i];
	pd(i,s,t);int mid=(s+t)>>1;ll tot=LLONG_MIN;
	if(mid>=l)tot=getmax(l,r,s,mid,(i<<1));
	if(mid+1<=r)tot=max(tot,getmax(l,r,mid+1,t,(i<<1)|1));
	return tot;
}
int main()
{
	int i,j,x,y;char ch;ll z;
	n=read();m=read();
	for(i=1;i<=n;i++)a[i]=read();
	build(1,n,1);
	for(i=1;i<=m;i++){
		ch=' ';
		while(ch<'a'||ch>'z')ch=getchar();
		if(ch=='a'){x=read();y=read();z=read();add(x,y,1,n,1,z);}
		else if(ch=='s'){
			ch=getchar();
			if(ch=='e'){x=read();y=read();z=read();chan(x,y,1,n,1,z);}
			else {x=read();y=read();printf("%lld\n",getsum(x,y,1,n,1));}
		}
		else if(ch=='m'){
			ch=getchar();
			if(ch=='i'){x=read();y=read();printf("%lld\n",getmin(x,y,1,n,1));}
			else {x=read();y=read();printf("%lld\n",getmax(x,y,1,n,1));}
		}
	}
   	return 0;
} 


你可能感兴趣的:(数据结构)