【线段树】区间加乘区间最大

线段树模板题(四)——区间加乘区间最大

【题目描述】  

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.将某区间每一个数乘上x

3.求出某区间每一个数的和

【输入】

第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k

操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果

【输出】

输出包含若干行整数,即为所有操作3的结果。

【样例输入】

5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4    

【样例输出】

17
2

【提示】

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

代码:

#include<bits/stdc++.h>
using namespace std;
#define lc (p<<1)
#define rc (p<<1|1)
long long n,m,a[100010],mod;
struct node{
	int l,r,mul,add;
	long long sum;
}T[100010*4]; 
inline void pushup(long long p){
	T[p].sum=T[lc].sum+T[rc].sum;
}
inline void pushadd(long long p,long long x){
	T[p].sum+=(T[p].r-T[p].l+1)*x%mod;
	T[p].add+=x;
}
inline void pushmul(long long p,long long x){
	T[p].sum*=x;
	T[p].sum%=mod;
	T[p].add*=x;
	T[p].add%=mod;
	T[p].mul*=x;
	T[p].mul%=mod;
}
inline void pushdown(long long p){
	if(T[p].mul!=1){
		T[lc].sum=T[lc].sum*T[p].mul%mod;
		T[lc].mul=T[lc].mul*T[p].mul%mod;
		T[lc].add=T[lc].add*T[p].mul%mod;
		T[rc].sum=T[rc].sum*T[p].mul%mod;
		T[rc].mul=T[rc].mul*T[p].mul%mod;
		T[rc].add=T[rc].add*T[p].mul%mod;
		T[p].mul=1;
	}
	if(T[p].add){
		T[lc].sum+=T[p].add*(T[lc].r-T[lc].l+1)%mod;
		T[lc].add+=T[p].add;
		T[rc].sum+=T[p].add*(T[rc].r-T[rc].l+1)%mod;
		T[rc].add+=T[p].add; 
		T[p].add=0;
	}
}
inline void build(long long p,long long l,long long r){
	T[p].l=l;
	T[p].r=r;
	T[p].add=0;
	T[p].mul=1;
	if(l==r){
		T[p].sum=a[l];
		return ;
	}
	long long mid=(l+r)>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	pushup(p);
}
inline void Add(long long p,long long l,long long r,long long x){
	if(l<=T[p].l&&T[p].r<=r){
		pushadd(p,x);
		return ;
	}
	long long mid=(T[p].l+T[p].r)>>1;
	pushdown(p);
	if(l<=mid) Add(lc,l,r,x);
	if(r>mid) Add(rc,l,r,x);
	pushup(p);
}//区间加 
inline void Mul(long long p,long long l,long long r,long long x){
	if(l<=T[p].l&&T[p].r<=r){
		pushmul(p,x);
		return ;
	}
	long long mid=(T[p].l+T[p].r)>>1;
	pushdown(p);
	if(l<=mid) Mul(lc,l,r,x);
	if(r>mid) Mul(rc,l,r,x);
	pushup(p);
}//	区间乘 
inline long long query(long long p,long long l,long long r){
	if(l<=T[p].l&&T[p].r<=r){
		return T[p].sum;
	}
	long long mid=(T[p].l+T[p].r)>>1,ans=0;
	pushdown(p);
	if(l<=mid) ans=(ans+query(lc,l,r))%mod;
	if(r>mid) ans=(ans+query(rc,l,r))%mod;
	pushup(p);
	return ans;
}//区间求和 
int main(){
	cin>>n>>m>>mod;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,1,n);
	for(int i=1;i<=m;i++){
		int k;
		cin>>k;
		if(k==1){
			int a,b,c;
			cin>>a>>b>>c;
			Mul(1,a,b,c);
		}
		if(k==2){
			int a,b,c;
			cin>>a>>b>>c;
			Add(1,a,b,c);
		} 
		if(k==3){
			int a,b;
			cin>>a>>b;
			cout<<query(1,a,b)<<endl;
		}
	} 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42754826/article/details/84678638