【题目链接】P3373 【模板】线段树 2
【思路】
本题复杂在于有两个优先级不同的区间修改操作。考虑遵循乘法优先,那么维护两个懒标记mul(乘)和add(加),打加法标记按照普通方法,打乘法标记要注意把加法标记也乘一下要乘的数。加法标记的下传,要先把原标记乘上乘法标记(乘法优先)
举个例子:
假设一个长度为5的区间的和为25,现要把区间每个数加上5再乘上5,那么打乘法标记时,加法标记就应变为5*5=25,那么维护该区间的值时,这个区间的值就应该是25*5+5*5*5=250,类似于乘法分配律的思想。先乘后加也是一样的推导:打乘法标记时,加法标记变为0*5=0,后来加法打上标记5,维护区间值时,这个区间的值就应该是25*5+5*5=150。
【Code】
#include<iostream>
#include<cstdio>
using namespace std;
struct Segment_Tree{
long long sum;
long long mul,add;
}tree[500000];
long long a[100100],kk;
int p,n,m,op,ll,rr;
inline void build(int k,int l,int r){
tree[k].add=0;
tree[k].mul=1;
if(l==r){
tree[k].sum=a[l]%p;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%p;
}
inline void pushdown(int k,int l,int r){
int mid=(l+r)>>1;
tree[k<<1].sum=(tree[k<<1].sum*tree[k].mul+tree[k].add*(mid-l+1))%p;
tree[k<<1|1].sum=(tree[k<<1|1].sum*tree[k].mul+tree[k].add*(r-mid))%p;
if(tree[k].add){
tree[k<<1].add=(tree[k<<1].add*tree[k].mul+tree[k].add)%p;
tree[k<<1|1].add=(tree[k<<1|1].add*tree[k].mul+tree[k].add)%p;
tree[k].add=0;
}
if(tree[k].mul!=1){
tree[k<<1].mul=(tree[k<<1].mul*tree[k].mul)%p;
tree[k<<1|1].mul=(tree[k<<1|1].mul*tree[k].mul)%p;
tree[k].mul=1;
}
}
inline long long Ask(int k,int l,int r,int x,int y){
if(x>r||l>y)return 0;
if(x<=l&&y>=r)return tree[k].sum;
pushdown(k,l,r);
int mid=(l+r)>>1;
long long res=0;
if(x<=mid)res+=Ask(k<<1,l,mid,x,y);
if(y>mid)res+=Ask(k<<1|1,mid+1,r,x,y);
return res%p;
}
inline void modify_add(int k,int l,int r,int x,int y,long long v){
if(y<l||r<x)return;
if(x<=l&&r<=y){
tree[k].add=(tree[k].add+v)%p;
tree[k].sum=(tree[k].sum+v*(r-l+1))%p;
return;
}
pushdown(k,l,r);
int mid=(l+r)>>1;
if(x<=mid)modify_add(k<<1,l,mid,x,y,v);
if(y>mid)modify_add(k<<1|1,mid+1,r,x,y,v);
tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%p;
}
inline void modify_mul(int k,int l,int r,int x,int y,long long v){
if(y<l||r<x)return;
if(x<=l&&r<=y){
tree[k].mul=(tree[k].mul*v)%p;
tree[k].sum=(tree[k].sum*v)%p;
tree[k].add=(tree[k].add*v)%p;
return;
}
pushdown(k,l,r);
int mid=(l+r)>>1;
if(x<=mid)modify_mul(k<<1,l,mid,x,y,v);
if(y>mid)modify_mul(k<<1|1,mid+1,r,x,y,v);
tree[k].sum=(tree[k<<1].sum+tree[k<<1|1].sum)%p;
}
int main(){
scanf("%d%d%d",&n,&m,&p);
for(register int i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
for(register int i=1;i<=m;i++){
scanf("%d",&op);
if(op==1){
scanf("%d%d%lld",&ll,&rr,&kk);
modify_mul(1,1,n,ll,rr,kk);
}
else{
if(op==2){
scanf("%d%d%lld",&ll,&rr,&kk);
modify_add(1,1,n,ll,rr,kk);
}
else{
scanf("%d%d",&ll,&rr);
printf("%lld\n",Ask(1,1,n,ll,rr));
}
}
}
return 0;
}