洛谷P3373 【模板】线段树 2
代码基本是跟着洛谷《深进》写的,改成了结构体的形式
样例是对的
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000010
typedef long long ll;
int n,q,m;ll a[MAXN];
struct node{
//sum表示区间和,lzy_add是加法的懒标记,lzy_mul是乘法的懒标记
ll sum,lzy_add,lzy_mul;
node(){sum=lzy_add=0;lzy_mul=1;}
}w[MAXN*4];
inline void pushup(const int u){//更新节点u的值
w[u].sum=(w[u<<1].sum+w[(u<<1)+1].sum)%m;
}
void build(const int u,int L,int R){//建立线段树
if(L==R){
w[u].sum=a[L];
return;
}
int M=L+R>>1;
build(u<<1,L,M);
build((u<<1)+1,M+1,R);
pushup(u);
}
//制作懒标记
inline void make_tag(const int u,int L,int R,int type,ll num){
if(type==1){//type=1表示*
w[u].sum*=num;
w[u].lzy_mul*=num;
w[u].lzy_add*=num;
}
else{//type=2表示+
w[u].sum+=(R-L+1)*num;
w[u].lzy_add+=num;
}
w[u].sum%=m;w[u].lzy_add%=m;w[u].lzy_mul%=m;
}
inline void pushdown(const int u,int L,int R){//懒标记下放
int M=L+R>>1;
make_tag(u<<1,L,M,2,w[u].lzy_add);
make_tag(u<<1,L,M,1,w[u].lzy_mul);
make_tag((u<<1)+1,M+1,R,2,w[u].lzy_add);
make_tag((u<<1)+1,M+1,R,1,w[u].lzy_mul);
w[u].lzy_add=0;w[u].lzy_mul=1;
}
bool InRange(int L,int R,int l,int r){//判断[L,R]是否完全被[l,r]包含
return l<=L&&R<=r;
}
bool OutofRange(int L,int R,int l,int r){//判断[L,R]与[l,r]完全无交集
return L>r||R<l;
}
ll query(const int u,int L,int R,int l,int r){//查询[l,r]的区间和
if(InRange(L,R,l,r))return w[u].sum;
else if(!OutofRange(L,R,l,r)){
int M=L+R>>1;
pushdown(u,L,R);
return (query(u<<1,L,M,l,r)+query((u<<1)+1,M+1,R,l,r))%m;
}
return 0;
}
//修改[l,r]
void update(const int u,int L,int R,int l,int r,int type,ll num){
if(InRange(L,R,l,r))make_tag(u,L,R,type,num);
else if(!OutofRange(L,R,l,r)){
int M=L+R>>1;
pushdown(u,L,R);
update(u<<1,L,M,l,r,type,num);
update((u<<1)+1,M+1,R,l,r,type,num);
pushup(u);
}
}
int main(){
scanf("%d%d%d",&n,&q,&m);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
while(q--){
int opt;
scanf("%d",&opt);
if(opt==1||opt==2){
int x,y;ll k;
scanf("%d%d%lld",&x,&y,&k);
update(1,1,n,x,y,opt,k);
}
else{
int x,y;
scanf("%d%d",&x,&y);
printf("%lld\n",query(1,1,n,x,y));
}
}
return 0;
}