给定一个长度为n的原序列和模数mod,m个操作,[a,b]区间乘c,[a,b]区间加c,统计[a,b]的区间和。
思路
线段树维护的还是区间和,但是这里我们需要用到两个懒标记,一个记录加法,一个记录乘法,乘法懒标记下传之后要重置为1而不是0。对于一个乘法操作,他影响的是区间和还有这个区间的加法标记、乘法标记。即如果原来这个区间的加法懒标记的值为1,然后传来了一个区间乘5的操作,那么这个加法懒标记也要乘5。
#include
using namespace std;
typedef long long ll;
const int N=1e6+5;
//const int mod=1e9+7;
const int INF=0x7fffffff;
const ll LLINF=0x7fffffffffffffff;
const double EPS=1e-10;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pb push_back
#define pii pair
#define pll pair
#define debug cout<<"debug"<
#define ls p<<1
#define rs p<<1|1
#define int long long
int a[N];int n,mod;
struct tree
{
int l,r,pre,add,mul=1;
}t[N<<2];
void build(int p,int x,int y)
{
t[p].l=x;t[p].r=y;
if(x==y)
{
t[p].pre=a[x]%mod;
return ;
}
int mid=x+y>>1;
build(ls,x,mid);
build(rs,mid+1,y);
t[p].pre=(t[ls].pre%mod+t[rs].pre%mod)%mod;
}
void spread(int p)
{
int t1=t[p].mul,t2=t[p].add;
t[ls].pre=(t[ls].pre*t1+t2*(t[ls].r-t[ls].l+1))%mod;
t[rs].pre=(t[rs].pre*t1+t2*(t[rs].r-t[rs].l+1))%mod;
t[ls].mul=t[ls].mul*t1%mod;
t[rs].mul=t[rs].mul*t1%mod;
t[ls].add=(t[ls].add*t1+t2)%mod;
t[rs].add=(t[rs].add*t1+t2)%mod;
t[p].add=0;t[p].mul=1;
return ;
}
void change1(int p,int x,int y,int z)
{
if(x<=t[p].l&&t[p].r<=y)
{
t[p].pre=t[p].pre*z%mod;
t[p].mul=z*t[p].mul%mod;
t[p].add=z*t[p].add%mod;
return ;
}
spread(p);
int mid=t[p].l+t[p].r>>1;
if(x<=mid)
change1(ls,x,y,z);
if(y>mid)
change1(rs,x,y,z);
t[p].pre=(t[ls].pre+t[rs].pre)%mod;
}
void change2(int p,int x,int y,int z)
{
if(x<=t[p].l&&t[p].r<=y)
{
t[p].pre=(t[p].pre+z*(t[p].r-t[p].l+1))%mod;
t[p].add=(t[p].add+z)%mod;
return ;
}
spread(p);
int mid=t[p].l+t[p].r>>1;
if(x<=mid)
change2(ls,x,y,z);
if(y>mid)
change2(rs,x,y,z);
t[p].pre=(t[ls].pre+t[rs].pre)%mod;
}
int ask(int p,int x,int y)
{
if(x<=t[p].l&&t[p].r<=y)
{
return t[p].pre;
}
spread(p);
int mid=t[p].l+t[p].r>>1;
int ans=0;
if(x<=mid)
ans=(ans+ask(ls,x,y))%mod;
if(y>mid)
ans=(ans+ask(rs,x,y))%mod;
return ans%mod;
}
signed main()
{
IOS;
//freopen("","r",stdin);
//freopen("","w",stdout);
scanf("%lld%lld",&n,&mod);
for(int i=1;i<=n;i++)
{
scanf("%lld",a+i);
}
build(1,1,n);
int m;
scanf("%lld",&m);
while(m--)
{
int oo,t,g,c;
scanf("%lld%lld%lld",&oo,&t,&g);
if(oo==1)
{
scanf("%lld",&c);
change1(1,t,g,c);
}
if(oo==2)
{
scanf("%lld",&c);
change2(1,t,g,c);
}
if(oo==3)
{
int res=ask(1,t,g);
printf("%lld\n",res);
}
}
}