题目
#include<cstdio>
#define lc o<<1
#define rc o<<1|1
typedef long long ll;
const int N=1e5+10;
int n,m;
ll p;
ll a[N],sum[N<<2],add[N<<2],mul[N<<2];
void build(int o,int l,int r)
{
add[o]=0;mul[o]=1;
if(l==r)
{
sum[o]=a[l]%p;
return;
}
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
sum[o]=(sum[lc]+sum[rc])%p;
}
void push_down(int o,int l,int r)
{
if(mul[o]!=1)
{
sum[lc]=sum[lc]*mul[o]%p;
sum[rc]=sum[rc]*mul[o]%p;
mul[lc]=mul[lc]*mul[o]%p;
mul[rc]=mul[rc]*mul[o]%p;
add[lc]=add[lc]*mul[o]%p;
add[rc]=add[rc]*mul[o]%p;
mul[o]=1;
}
int mid=l+r>>1;
if(add[o])
{
sum[lc]=(sum[lc]+add[o]*(mid-l+1))%p;
sum[rc]=(sum[rc]+add[o]*(r-mid))%p;
add[lc]=(add[lc]+add[o])%p;
add[rc]=(add[rc]+add[o])%p;
add[o]=0;
}
}
void upmul(int o,int l,int r,int nl,int nr,ll c)
{
if(nl<=l&&r<=nr)
{
sum[o]=sum[o]*c%p;
mul[o]=mul[o]*c%p;
add[o]=add[o]*c%p;
return;
}
push_down(o,l,r);
int mid=l+r>>1;
if(nl<=mid)upmul(lc,l,mid,nl,nr,c);
if(nr>mid)upmul(rc,mid+1,r,nl,nr,c);
sum[o]=(sum[lc]+sum[rc])%p;
}
void upadd(int o,int l,int r,int nl,int nr,ll c)
{
if(nl<=l&&r<=nr)
{
sum[o]=(sum[o]+(r-l+1)*c)%p;
add[o]=(add[o]+c)%p;
return;
}
push_down(o,l,r);
int mid=l+r>>1;
if(nl<=mid)upadd(lc,l,mid,nl,nr,c);
if(nr>mid)upadd(rc,mid+1,r,nl,nr,c);
sum[o]=(sum[lc]+sum[rc])%p;
}
ll query(int o,int l,int r,int nl,int nr)
{
if(nl<=l&&r<=nr)return sum[o]%p;
push_down(o,l,r);
int mid=l+r>>1;
ll ans=0;
if(nl<=mid)ans=(ans+query(lc,l,mid,nl,nr))%p;
if(nr>mid)ans=(ans+query(rc,mid+1,r,nl,nr))%p;
return ans%p;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%lld",&n,&p);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
build(1,1,n);
scanf("%d",&m);
int op,t,g;
ll c;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&op,&t,&g);
if(op==1)scanf("%lld",&c),upmul(1,1,n,t,g,c);
else if(op==2)scanf("%lld",&c),upadd(1,1,n,t,g,c);
else printf("%lld\n",query(1,1,n,t,g));
}
return 0;
}
总结
裸的线段树区间增乘模板题。