所有的操作都没什么很大的变化
我们处理加法和乘法的时候,默认乘法操作优先于加法操作
在计算一个结点的值的时候:
val=val*mul+len*add
mul:乘法标记
len:区间长度
add:加法标记
在下传标记的时候,
儿子的值我们也是按照上面那样算
整个算法中,最难的就是儿子的标记维护
开ll
随时%
mul标记的初始值是1,add标记初始值是0
在修改值的时候,add的维护需要累加,mul的维护需要累乘
//这里写代码片
#include
#include
#include
#define ll long long
using namespace std;
const int N=100010;
struct node{
int x,y;
ll v,mul,ad;
};
node t[N<<2];
int n,m;
ll a[N],p;
void update(int bh)
{
t[bh].v=t[bh<<1].v+t[(bh<<1)+1].v;
t[bh].v%=p;
}
void push(int bh) //默认乘操作在加操作之前
{
int lc=bh<<1;
int rc=(bh<<1)+1;
if (t[bh].mul!=1||t[bh].ad!=0)
{
t[lc].v=( (t[lc].v*t[bh].mul)%p + ((t[lc].y-t[lc].x+1)*t[bh].ad)%p )%p;
t[lc].mul=(t[bh].mul*t[lc].mul)%p;
t[lc].ad=(t[lc].ad*t[bh].mul)%p+t[bh].ad; t[lc].ad%=p;
t[rc].v=( (t[rc].v*t[bh].mul)%p + ((t[rc].y-t[rc].x+1)*t[bh].ad)%p )%p;
t[rc].mul=(t[bh].mul*t[rc].mul)%p;
t[rc].ad=(t[rc].ad*t[bh].mul)%p+t[bh].ad; t[rc].ad%=p;
t[bh].ad=0;
t[bh].mul=1;
}
return;
}
void build(int bh,int l,int r)
{
t[bh].x=l;
t[bh].y=r;
t[bh].mul=1; t[bh].ad=0;
if (l==r)
{
t[bh].v=a[l]%p;
return;
}
int mid=(l+r)>>1;
build(bh<<1,l,mid);
build(bh<<1|1,mid+1,r);
update(bh);
}
void add(int bh,int l,int r,ll val)
{
push(bh);
if (t[bh].x>=l&&t[bh].y<=r)
{
t[bh].ad+=val; t[bh].ad%=p;
t[bh].v=( t[bh].v*t[bh].mul%p + ((t[bh].y-t[bh].x+1)*t[bh].ad)%p )%p;
return;
}
int mid=(t[bh].x+t[bh].y)>>1;
if (l<=mid) add(bh<<1,l,r,val);
if (r>mid) add((bh<<1)+1,l,r,val);
update(bh);
}
void multi(int bh,int l,int r,ll val)
{
push(bh);
if (t[bh].x>=l&&t[bh].y<=r)
{
t[bh].mul*=val; t[bh].mul%=p;
t[bh].v=( t[bh].v*t[bh].mul%p + ((t[bh].y-t[bh].x+1)*t[bh].ad)%p )%p;
return;
}
int mid=(t[bh].x+t[bh].y)>>1;
if (l<=mid) multi(bh<<1,l,r,val);
if (r>mid) multi((bh<<1)+1,l,r,val);
update(bh);
}
int ask(int bh,int l,int r)
{
push(bh);
if (t[bh].x>=l&&t[bh].y<=r)
return t[bh].v%p;
ll ans=0;
int mid=(t[bh].x+t[bh].y)>>1;
if (l<=mid) ans+=ask(bh<<1,l,r);
if (r>mid) ans+=ask((bh<<1)+1,l,r);
return ans%p;
}
int main()
{
scanf("%d%d%lld",&n,&m,&p);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
int opt,x,y;
ll z;
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&opt,&x,&y);
if (opt==3){
printf("%lld\n",ask(1,x,y)%p);
}
else if (opt==2)
{
scanf("%lld",&z);
add(1,x,y,z%p);
}
else
{
scanf("%lld",&z);
multi(1,x,y,z%p);
}
}
return 0;
}