BZOJ 1798 [Ahoi2009]Seq 维护序列seq
2017.09.12
2017.09.12
维护一个序列,支持:区间每个数加上某个数,乘以某个数,查询某区间的和。
双标记线段树板子题。直接维护就可以了。
注意对称的东西在复制粘贴的时候不!能!写!错!
#include <cstdio>
#include <algorithm>
using namespace std;
#define lson pos<<1
#define rson pos<<1|1
#define maxN 100010
int inx,iny,inz,mode,mo,n,m,a[maxN];
long long val[maxN<<2],lazup[maxN<<2],lazmul[maxN<<2];
void pushup(int pos) {val[pos]=(val[lson]+val[rson])%mo;}
void pushdown(int pos,int l,int r)
{
int mid=(l+r)>>1;
if(lazmul[pos]!=1)
{
lazup[lson]=(lazup[lson]*lazmul[pos])%mo;
lazup[rson]=(lazup[rson]*lazmul[pos])%mo;
val[lson]=(val[lson]*lazmul[pos])%mo,val[rson]=(val[rson]*lazmul[pos])%mo;
lazmul[lson]=(lazmul[lson]*lazmul[pos])%mo,lazmul[rson]=(lazmul[rson]*lazmul[pos])%mo;
lazmul[pos]=1;
}
if(lazup[pos])
{
val[lson]=(val[lson]+lazup[pos]*(mid-l+1))%mo,val[rson]=(val[rson]+lazup[pos]*(r-mid))%mo;
lazup[lson]=(lazup[lson]+lazup[pos])%mo,lazup[rson]=(lazup[rson]+lazup[pos])%mo;
lazup[pos]=0;
}
}
void mul(int pos,int l,int r,int x,int y,int z)
{
if(x<=l&&r<=y)
{
lazup[pos]=(lazup[pos]*z)%mo,lazmul[pos]=(lazmul[pos]*z)%mo,val[pos]=(val[pos]*z)%mo;
return;
}
pushdown(pos,l,r);
int mid=(l+r)>>1;
if(x<=mid) mul(lson,l,mid,x,y,z);
if(y>mid) mul(rson,mid+1,r,x,y,z);
pushup(pos);
}
void add(int pos,int l,int r,int x,int y,int z)
{
if(x<=l&&r<=y)
{
lazup[pos]=(lazup[pos]+z)%mo,val[pos]=(val[pos]+1ll*z*(r-l+1))%mo;
return;
}
pushdown(pos,l,r);
int mid=(l+r)>>1;
if(x<=mid) add(lson,l,mid,x,y,z);
if(y>mid) add(rson,mid+1,r,x,y,z);
pushup(pos);
}
void build(int pos,int l,int r)
{
lazmul[pos]=1;
if(l==r)
{
val[pos]=a[l];
return;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(pos);
}
long long query(int pos,int l,int r,int x,int y)
{
if(x<=l&&r<=y) return val[pos];
pushdown(pos,l,r);
int mid=(l+r)>>1;
long long ret=0;
if(x<=mid) ret=(ret+query(lson,l,mid,x,y))%mo;
if(y>mid) ret=(ret+query(rson,mid+1,r,x,y))%mo;
return ret;
}
int main()
{
scanf("%d%d",&n,&mo);
for(int i=1;i<=n;++i)scanf("%d",a+i);
build(1,1,n);
scanf("%d",&m);
while(m--)
{
scanf("%d",&mode);
switch(mode)
{
case 1:{scanf("%d%d%d",&inx,&iny,&inz),mul(1,1,n,inx,iny,inz);break;}
case 2:{scanf("%d%d%d",&inx,&iny,&inz),add(1,1,n,inx,iny,inz);break;}
case 3:{scanf("%d%d",&inx,&iny),printf("%lld\n",query(1,1,n,inx,iny)%mo);break;}
}
}
return 0;
}