坑点:区间可能乘0,不能用乘法标记大于1作为下传条件,下传条件应该为乘法标记不等于1。
做法:维护标记时,操作为乘:乘法标记直接修改,加法标记也要乘操作数;操作为加:只改加法标记。
下传标记时:分别修改两个子节点的值,先下传乘法标记,再下传加法标记。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll mod,c;
int t,g,op;
struct node
{
ll v,mul,add;
}tree[400010];
void build(int l,int r,int now)
{
tree[now].mul=1;
tree[now].add=0;
if(l==r)
{
scanf("%lld",&tree[now].v);
tree[now].v=tree[now].v%mod;
return;
}
int mid=(l+r)>>1;
build(l,mid,now<<1);
build(mid+1,r,now<<1|1);
tree[now].v=(tree[now<<1].v+tree[now<<1|1].v)%mod;
}
void pushdown(int now,int l,int r,int l1,int l2)
{
tree[l].v=((tree[l].v*tree[now].mul)%mod+(l1*tree[now].add)%mod)%mod;
tree[l].mul=(tree[now].mul*tree[l].mul)%mod;
tree[l].add=(tree[now].mul*tree[l].add)%mod;
tree[l].add=(tree[now].add+tree[l].add)%mod;
tree[r].v=((tree[r].v*tree[now].mul)%mod+(l2*tree[now].add)%mod)%mod;
tree[r].mul=(tree[now].mul*tree[r].mul)%mod;
tree[r].add=(tree[now].mul*tree[r].add)%mod;
tree[r].add=(tree[now].add+tree[r].add)%mod;
tree[now].mul=1;
tree[now].add=0;
}
void change(int l,int r,int now)
{
// cout<<l<<' '<<r<<' '<<tree[now].v<<endl;
if(l==r)
{
//cout<<'a'<<' '<<l<<' '<<r<<' '<<tree[now].v<<endl;
if(op==1)
tree[now].v=(tree[now].v*c)%mod;
else
tree[now].v=(tree[now].v+c)%mod;
return;
}
if(t<=l&&r<=g)
{
// cout<<'a'<<' '<<l<<' '<<r<<' '<<tree[now].v<<endl;
if(op==1)
{
tree[now].mul=(tree[now].mul*c)%mod;
tree[now].add=(tree[now].add*c)%mod;
tree[now].v=(tree[now].v*c)%mod;
}
else
{
tree[now].add=(tree[now].add+c)%mod;
tree[now].v=(tree[now].v+(c*(r-l+1))%mod)%mod;
}
return;
}
int mid=(l+r)>>1;
if(tree[now].mul!=1||tree[now].add)
pushdown(now,now<<1,now<<1|1,mid-l+1,r-mid);
if(t<=mid)
change(l,mid,now<<1);
if(g>mid)
change(mid+1,r,now<<1|1);
tree[now].v=(tree[now<<1].v+tree[now<<1|1].v)%mod;
}
int query(int l,int r,int now)
{
if(t<=l&&r<=g)
{
// cout<<l<<' '<<r<<' '<<tree[now].v<<endl;
return tree[now].v;
}
int mid=(l+r)>>1;
if(tree[now].mul!=1||tree[now].add)
pushdown(now,now<<1,now<<1|1,mid-l+1,r-mid);
if(g<=mid)
return query(l,mid,now<<1);
else if(t>mid)
return query(mid+1,r,now<<1|1);
else
return (query(l,mid,now<<1)%mod+query(mid+1,r,now<<1|1)%mod)%mod;
}
int main()
{
//freopen("1.txt","r",stdin);
int n,m;
cin>>n>>mod;
build(1,n,1);
cin>>m;
while(m--)
{
scanf("%d",&op);
if(op!=3)
{
scanf("%d%d%lld",&t,&g,&c);
c=c%mod;
change(1,n,1);
}
else
{
scanf("%d%d",&t,&g);
printf("%d\n",query(1,n,1));
}
//show(1,n,1);
//cout<<endl;
}
return 0;
}