传送门
分析:
因为同时涉及两种区间更新操作,故考虑用两种$lazytag$去打标记。
而在我们进行区间加和区间乘的时候,我们会发现,因为乘法的优先级较加法的优先级要高,因此,为了方便处理,我们优先选择下放乘法标记。
同时我们需要注意,在我们下放乘法标记$mul$的时候,如果当前区间存在加法标记$add$,则我们需要在$add$的基础上乘上$mul$
#include <bits/stdc++.h>
using namespace std;
const int maxn=100005;
int mod;
typedef long long ll;
struct St{
int rt,len;
ll mul,sum,add;
}tr[maxn<<2];
int a[maxn];
void push_up(int rt){
tr[rt].sum=(tr[rt<<1].sum+tr[rt<<1|1].sum)%mod;
}
void push_down(int rt){
if(tr[rt].mul!=1){
tr[rt<<1].mul=(tr[rt<<1].mul*tr[rt].mul)%mod;
tr[rt<<1|1].mul=(tr[rt<<1|1].mul*tr[rt].mul)%mod;
tr[rt<<1].add=(tr[rt<<1].add*tr[rt].mul)%mod;
tr[rt<<1|1].add=(tr[rt<<1|1].add*tr[rt].mul)%mod;
tr[rt<<1].sum=(tr[rt<<1].sum*tr[rt].mul)%mod;
tr[rt<<1|1].sum=(tr[rt<<1|1].sum*tr[rt].mul)%mod;
tr[rt].mul=1;
}
if(tr[rt].add){
tr[rt<<1].add=(tr[rt<<1].add+tr[rt].add)%mod;
tr[rt<<1|1].add=(tr[rt<<1|1].add+tr[rt].add)%mod;
tr[rt<<1].sum=(tr[rt<<1].sum+tr[rt<<1].len*tr[rt].add%mod)%mod;
tr[rt<<1|1].sum=(tr[rt<<1|1].sum+tr[rt<<1|1].len*tr[rt].add%mod)%mod;
tr[rt].add=0;
}
}
void build(int l,int r,int rt){
tr[rt].len=r-l+1;
tr[rt].mul=1;
tr[rt].add=0;
if(l==r){
tr[rt].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
push_up(rt);
}
void update1(int L,int R,int l,int r,int rt,int x){
if(L<=l&&R>=r){
tr[rt].sum=tr[rt].sum+x*tr[rt].len%mod;
tr[rt].add=(tr[rt].add+x)%mod;
return ;
}
push_down(rt);
int mid=(l+r)>>1;
if(L<=mid) update1(L,R,l,mid,rt<<1,x);
if(R>mid) update1(L,R,mid+1,r,rt<<1|1,x);
push_up(rt);
}
void update2(int L,int R,int l,int r,int rt,int x){
if(L<=l&&R>=r){
tr[rt].mul=tr[rt].mul*x%mod;
tr[rt].add=tr[rt].add*x%mod;
tr[rt].sum=tr[rt].sum*x%mod;
return;
}
int mid=(l+r)>>1;
push_down(rt);
if(L<=mid) update2(L,R,l,mid,rt<<1,x);
if(R>mid) update2(L,R,mid+1,r,rt<<1|1,x);
push_up(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r){
return tr[rt].sum%mod;
}
int mid=(l+r)>>1;
push_down(rt);
ll res=0;
if(L<=mid) res=(query(L,R,l,mid,rt<<1)+res)%mod;
if(R>mid) res=(query(L,R,mid+1,r,rt<<1|1)+res)%mod;
return res;
}
int main()
{
int n,m;
scanf("%d%d",&n,&mod);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
build(1,n,1);
scanf("%d",&m);
while(m--){
int op,l,r,num;
scanf("%d%d%d",&op,&l,&r);
if(op==1){
scanf("%d",&num);
update2(l,r,1,n,1,num);
}
else if(op==2){
scanf("%d",&num);
update1(l,r,1,n,1,num);
}
else{
printf("%lld
",query(l,r,1,n,1)%mod);
}
}
return 0;
}