题目简介:我们要一个能同时支持加法与乘法的区间修改并查询区间求和的线段树。
解题思路:这题目涉及到加法和乘法的前后顺序。这会直接导致答案的不同。于是有两种顺序:先加再乘or先乘再加。我们选择后者。因为前者的tag维护十分的不方便,每次加都对于后面的乘会有极大的影响。后者则不存在这些问题。维护的时候也按照这个顺序维护。所以直接上代码。
#include<iostream> #include<cstdio> #include<cmath> #define cm long long mid=(l+r)>>1 #define zc k<<1 #define yc (k<<1)+1 #define din l>=z&&r<=y #define dout r<z||l>y using namespace std; long long read(){ char ch; long long res=0,f=1; ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ res=res*10+(ch-'0'); ch=getchar(); } return res*f; } const long long MAXN=1<<30; long long n,m,a[400005],xds_sum[400005],p,tag_x[400005],tag_add[400005]; void pushdown(long long k,long long l,long long r){ if(tag_x[k]==1&&tag_add[k]==0)return; cm; xds_sum[zc]=((xds_sum[zc]*tag_x[k])%p+(tag_add[k]*(mid-l+1))%p)%p; xds_sum[yc]=((xds_sum[yc]*tag_x[k])%p+(tag_add[k]*(r-mid))%p)%p; tag_x[zc]=(tag_x[zc]*tag_x[k])%p; tag_x[yc]=(tag_x[yc]*tag_x[k])%p; tag_add[zc]=(tag_add[zc]*tag_x[k]+tag_add[k])%p; tag_add[yc]=(tag_add[yc]*tag_x[k]+tag_add[k])%p; tag_x[k]=1;tag_add[k]=0; } void build(long long k,long long l,long long r){ tag_x[k]=1; if(l==r){xds_sum[k]=a[l];return ;} cm; build(zc,l,mid);build(yc,mid+1,r); xds_sum[k]=(xds_sum[zc]+xds_sum[yc])%p; } long long query(long long k,long long l,long long r,long long z,long long y){ if(din)return xds_sum[k]; if(dout)return 0; cm; pushdown(k,l,r); return (query(zc,l,mid,z,y)+query(yc,mid+1,r,z,y))%p; } void change_add(long long k,long long l,long long r,long long z,long long y,long long v){ if(dout)return; if(din){ tag_add[k]=(tag_add[k]+v)%p; xds_sum[k]=(xds_sum[k]+v*(r-l+1))%p; return; } cm; pushdown(k,l,r); change_add(zc,l,mid,z,y,v); change_add(yc,mid+1,r,z,y,v); xds_sum[k]=(xds_sum[zc]+xds_sum[yc])%p; } void change_x(long long k,long long l,long long r,long long z,long long y,long long v){ if(dout)return; if(din){ tag_add[k]=(tag_add[k]*v)%p; tag_x[k]=(tag_x[k]*v)%p; xds_sum[k]=(xds_sum[k]*v)%p; return; } cm; pushdown(k,l,r); change_x(zc,l,mid,z,y,v); change_x(yc,mid+1,r,z,y,v); xds_sum[k]=(xds_sum[zc]+xds_sum[yc])%p; } int main(){ n=read();p=read(); for(long long i=1;i<=n;++i)a[i]=read(); build(1,1,n); m=read(); for(long long i=1;i<=m;++i){ long long order,x,y,g; order=read();x=read();y=read(); if(order==1){ g=read(); change_x(1,1,n,x,y,g); } else if(order==2){ g=read(); change_add(1,1,n,x,y,g); } else{ cout<<query(1,1,n,x,y)<<endl; } } return 0; }