线段树模板题(四)——区间加乘区间最大
【题目描述】
如题,已知一个数列,你需要进行下面两种操作:
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;
}