RT,马蜂良好,注释详细
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<queue>
#include<stack>
#include<time.h>
#define INF 0x3f3f3f3f
#define int long long
#define MAXN 400001
#define ls(x) f[x].l //左儿子
#define rs(x) f[x].r //右儿子
using namespace std;
int n,m,mod;//膜数
int add[MAXN];//加的lazy标记
int mul[MAXN];//乘的lazy标记
struct kx{
int l,r;//左儿子,右儿子编号
int v;//区间和
}f[MAXN];//动态开点线段树
int gen;//根
void up(int p){//算编号为q的区间和
f[p].v=(f[ls(p)].v+f[rs(p)].v)%mod;//左儿子区间和+右儿子区间和
}
void down(int p,int l,int r){//标记下传,编号,左端点,右端点。
if(add[p]||mul[p]!=1){//如果有lazy标记
int m=(l+r)/2;//取中间点
mul[ls(p)]=(mul[ls(p)]*mul[p])%mod;//先传乘
add[ls(p)]=(add[ls(p)]*mul[p])%mod;//传加,要算上乘lazy标记
add[ls(p)]=(add[ls(p)]+add[p])%mod;//传加
f[ls(p)].v=(f[ls(p)].v*mul[p])%mod;//更新区间和(乘)
f[ls(p)].v=(f[ls(p)].v+(m-l+1)*add[p])%mod;//更新区间和(加)
mul[rs(p)]=(mul[rs(p)]*mul[p])%mod;//先传乘
add[rs(p)]=(add[rs(p)]*mul[p])%mod;//传加,要算上乘lazy标记
add[rs(p)]=(add[rs(p)]+add[p])%mod;//传加
f[rs(p)].v=(f[rs(p)].v*mul[p])%mod;//更新区间和(乘)
f[rs(p)].v=(f[rs(p)].v+(r-m)*add[p])%mod;//更新区间和(加)
mul[p]=1;
add[p]=0;//清空lazy标记
}
}
void build(int &p,int l,int r){//编号,左端点,右端点(建树)
add[p]=0,mul[p]=0;//清空lazy标记
if(l==r){
scanf("%lld",&f[p].v);
return ;
}
int m=(l+r)/2;//取中间点
build(ls(p),l,m);//递归左儿子
build(rs(p),m+1,r);//递归右儿子
up(p);//更新区间和
}
void update(int p,int l,int r,int x,int y,int val,int c){
//编号,左端点,右端点,左端点(运算),右端点(运算),运算的值,运算类型(1为加,2为乘)
if(y<l||x>r) return ;//当前区间与运算区间完全不重叠
if(x<=l&&r<=y){//当前区间被运算区间完全包含
if(c==1){//加
add[p]=(add[p]+val)%mod;//打上lazy标记(加)
f[p].v=(f[p].v+(long long)(r-l+1)*val)%mod;//更新区间和
}else{//乘
add[p]=(add[p]*val)%mod;//打上lazy标记(加)
mul[p]=(mul[p]*val)%mod;//打上lazy标记(乘)
f[p].v=(f[p].v*val)%mod;//更新区间和
}
return ;
}
down(p,l,r);//标记下传
int m=(l+r)/2;//取中点
update(ls(p),l,m,x,y,val,c);//递归左端点
update(rs(p),m+1,r,x,y,val,c);//递归右端点
up(p);//更新区间和
}
int query_sum(int p,int l,int r,int x,int y){//查询区间和
//编号,左端点,右端点,左端点(查询),右端点(查询)
if(y<l||x>r) return 0;//当前区间与查询区间完全不重叠
if(x<=l&&r<=y){//当前区间完全被查询区间包含
return f[p].v;
}
down(p,l,r);//标记下传
int m=(l+r)/2;//取中点
int ret=0;
ret=(ret+query_sum(ls(p),l,m,x,y))%mod;//加上左端点区间和
ret=(ret+query_sum(rs(p),m+1,r,x,y))%mod;//加上右端点区间和
return ret;
}
signed main(){
ios::sync_with_stdio(false);
srand(time(NULL));
cin>>n>>mod;
build(gen,1,n);//建树
cin>>m;
for(int i=1,opd,l,r,val;i<=m;i++){
cin>>opd;//运算类型
if(opd==1){//乘
cin>>l>>r>>val;//左端点,右端点,运算的值
update(1,1,n,l,r,val,2);//修改
}else if(opd==2){//加
cin>>l>>r>>val;//左端点,右端点,运算的值
update(1,1,n,l,r,val,1);//修改
}else{
cin>>l>>r;//左端点,右端点
cout<<query_sum(1,1,n,l,r)<<"\n";//查询
}
}
return 0;
}