题目大意:有长为N的数列,有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
思路:用线段树来维护当前的值和要加以及乘的值,由于加与乘是有序的,所以要在做子树之前将标记下传,加和乘分开来、合起来处理都可以。
代码:(当初手抽将1打成l一直RE调了半天才发现)
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAX 400000
#define LL long long
using namespace std;
LL sum[MAX],mul[MAX],add[MAX],mod;
void up_date(int cur)
{
sum[cur]=(sum[cur<<1]+sum[cur<<1|1])%mod;
}
void creat(int L,int R,int x,int y,int cur)
{
mul[cur]=1;
add[cur]=0;
sum[cur]+=y;
if (L==R) return;
int mid=L+R>>1;
if (x>mid) creat(mid+1,R,x,y,cur<<1|1);
else creat(L,mid,x,y,cur<<1);
up_date(cur);
}
void push_down(int cur,int l,int r,int mid)
{
if (mul[cur]==1 && add[cur]==0) return;
mul[cur<<1]=mul[cur<<1]*mul[cur]%mod;
add[cur<<1]=(add[cur<<1]*mul[cur]%mod+add[cur])%mod;
sum[cur<<1]=(sum[cur<<1]*mul[cur]%mod+add[cur]*(LL)(mid-l+1)%mod)%mod;
mul[cur<<1|1]=mul[cur<<1|1]*mul[cur]%mod;
add[cur<<1|1]=(add[cur<<1|1]*mul[cur]%mod+add[cur])%mod;
sum[cur<<1|1]=(sum[cur<<1|1]*mul[cur]%mod+add[cur]*(LL)(r-mid)%mod)%mod;
mul[cur]=1;
add[cur]=0;
return;
}
void change_mul(int L,int R,int l,int r,int x,int cur)
{
if (L>=l && R<=r)
{
mul[cur]=mul[cur]*(LL)x%mod;
add[cur]=add[cur]*(LL)x%mod;
sum[cur]=sum[cur]*(LL)x%mod;
return;
}
int mid=L+R>>1;
push_down(cur,L,R,mid);
if (l<=mid) change_mul(L,mid,l,r,x,cur<<1);
if (r>mid) change_mul(mid+1,R,l,r,x,cur<<1|1);
up_date(cur);
}
void change_add(int L,int R,int l,int r,int x,int cur)
{
if (L>=l && R<=r)
{
add[cur]=(add[cur]+(LL)x)%mod;
sum[cur]=(sum[cur]+(LL)(R-L+1)*x%mod)%mod;
return;
}
int mid=L+R>>1;
push_down(cur,L,R,mid);
if (l<=mid) change_add(L,mid,l,r,x,cur<<1);
if (r>mid) change_add(mid+1,R,l,r,x,cur<<1|1);
up_date(cur);
}
LL ask(int L,int R,int l,int r,int cur)
{
if (L>=l && R<=r) return sum[cur];
int mid=L+R>>1;
LL ans=0;
push_down(cur,L,R,mid);
if (l<=mid) ans=(ans+ask(L,mid,l,r,cur<<1))%mod;
if (r>mid) ans=(ans+ask(mid+1,R,l,r,cur<<1|1))%mod;
up_date(cur);
return ans;
}
int main()
{
int n,m,a,b,c,i,x;
scanf("%d%lld",&n,&mod);
for (i=1;i<=n;i++) scanf("%d",&a),creat(1,n,i,a%mod,1);
scanf("%d",&m);
for (i=1;i<=m;i++)
{
scanf("%d",&x);
if (x==1) scanf("%d%d%d",&a,&b,&c),change_mul(1,n,a,b,c%mod,1);
if (x==2) scanf("%d%d%d",&a,&b,&c),change_add(1,n,a,b,c%mod,1);
if (x==3) scanf("%d%d",&a,&b),printf("%lld\n",ask(1,n,a,b,1));
}
return 0;
}