传送门
裸的线段树,每个节点打标记add和mul,注意下传即可。
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=100010;
struct node{
int L,R;
ll sum,add,mul;
}t[N*4];
int a[N],mo,n,m;
void pushup(int p){
t[p].sum=(t[p<<1].sum+t[p<<1|1].sum)%mo;
}
void update1(int p,ll d){
int len=t[p].R-t[p].L+1;
t[p].sum=(t[p].sum+d*len%mo)%mo;
t[p].add=(t[p].add+d)%mo;
}
void update2(int p,ll d){
t[p].sum=(t[p].sum*d)%mo;
t[p].add=(t[p].add*d)%mo;
t[p].mul=(t[p].mul*d)%mo;
}
void pushdown(int p){
update2(p<<1,t[p].mul);
update2(p<<1|1,t[p].mul);
t[p].mul=1;
update1(p<<1,t[p].add);
update1(p<<1|1,t[p].add);
t[p].add=0;
}
void build(int p,int L,int R){
if(L==R){
t[p].L=t[p].R=L;
t[p].sum=a[L];
t[p].add=0;
t[p].mul=1;
return;
}
int mid=L+R>>1;
build(p<<1,L,mid);
build(p<<1|1,mid+1,R);
t[p].L=L;
t[p].R=R;
t[p].mul=1;
t[p].add=0;
pushup(p);
}
void add(int p,int L,int R,int d){
int n_L=t[p].L;
int n_R=t[p].R;
if(L<=n_L && n_R<=R){
update1(p,d);
return;
}
pushdown(p);
int mid=n_L+n_R>>1;
if(L<=mid)add(p<<1,L,R,d);
if(mid<R)add(p<<1|1,L,R,d);
pushup(p);
}
void mul(int p,int L,int R,int d){
int n_L=t[p].L;
int n_R=t[p].R;
if(L<=n_L && n_R<=R){
update2(p,d);
return;
}
pushdown(p);
int mid=n_L+n_R>>1;
if(L<=mid)mul(p<<1,L,R,d);
if(mid<R)mul(p<<1|1,L,R,d);
pushup(p);
}
int sum(int p,int L,int R){
int n_L=t[p].L;
int n_R=t[p].R;
if(L<=n_L && n_R<=R)return t[p].sum;
pushdown(p);
int mid=n_L+n_R>>1;
ll ret=0;
if(L<=mid)ret=(ret+sum(p<<1,L,R))%mo;
if(mid<R) ret=(ret+sum(p<<1|1,L,R))%mo;
return ret;
}
int main(){
scanf("%d%d",&n,&mo);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
build(1,1,n);
scanf("%d",&m);
for(int i=1;i<=m;i++){
int fg,L,R,d;
scanf("%d",&fg);
switch(fg){
case 1:{
scanf("%d%d%d",&L,&R,&d);
mul(1,L,R,d);
break;
}
case 2:{
scanf("%d%d%d",&L,&R,&d);
add(1,L,R,d);
break;
}
case 3:{
scanf("%d%d",&L,&R);
printf("%d\n",sum(1,L,R));
break;
}
}
}
}