欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ1798
题意概括
一个序列n个数,支持3种操作:
1. 询问区间和
2. 修改区间: 每一个数加上一个数
3. 修改区间: 每一个数乘上一个数
n,m<=100000
题解
线段树。
懒标记维护两个,一个是加的数,一个是乘的倍数,我写的是先乘后加。
下传的时候也是先乘后加。
代码
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long LL;
const int N=100000+5;
int n,m,q;
LL mod,a[N];
struct SegTree{
int L,R,S;
LL v,addp,addt;
}t[N*4];
void build(int rt,int le,int ri){
t[rt].L=le,t[rt].R=ri,t[rt].S=ri-le+1;
t[rt].addp=0,t[rt].addt=1;
if (le==ri){
t[rt].v=a[le];
return;
}
int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
build(ls,le,mid);
build(rs,mid+1,ri);
t[rt].v=(t[ls].v+t[rs].v)%mod;
}
void pushdown(int rt){
int ls=rt<<1,rs=ls|1;
LL &adp=t[rt].addp,&adt=t[rt].addt;
LL &Lv=t[ls].v,&Lp=t[ls].addp,&Lt=t[ls].addt;
LL &Rv=t[rs].v,&Rp=t[rs].addp,&Rt=t[rs].addt;
if (adt!=1){
Lv=Lv*adt%mod;
Lp=Lp*adt%mod;
Lt=Lt*adt%mod;
Rv=Rv*adt%mod;
Rp=Rp*adt%mod;
Rt=Rt*adt%mod;
}
if (adp!=0){
Lv=(Lv+adp*t[ls].S)%mod;
Lp=(Lp+adp)%mod;
Rv=(Rv+adp*t[rs].S)%mod;
Rp=(Rp+adp)%mod;
}
adp=0,adt=1;
}
void update(int rt,int le,int ri,int xle,int xri,LL x,int type){
if (le>xri||ri<xle)
return;
if (xle<=le&&ri<=xri){
if (type==1){
t[rt].v=t[rt].v*x%mod;
t[rt].addp=t[rt].addp*x%mod;
t[rt].addt=t[rt].addt*x%mod;
}
else {
t[rt].v=(t[rt].v+x*t[rt].S)%mod;
t[rt].addp=(t[rt].addp+x)%mod;
}
return;
}
pushdown(rt);
int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
update(ls,le,mid,xle,xri,x,type);
update(rs,mid+1,ri,xle,xri,x,type);
t[rt].v=(t[ls].v+t[rs].v)%mod;
}
LL query(int rt,int le,int ri,int xle,int xri){
if (le>xri||ri<xle)
return 0;
if (xle<=le&&ri<=xri)
return t[rt].v;
pushdown(rt);
int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
return (query(ls,le,mid,xle,xri)+query(rs,mid+1,ri,xle,xri))%mod;
}
int main(){
scanf("%d%lld",&n,&mod);
for (int i=1;i<=n;i++)
scanf("%lld",&a[i]),a[i]%=mod;
build(1,1,n);
scanf("%d",&m);
for (int i=1;i<=m;i++){
int type,L,R;
LL c;
scanf("%d%d%d",&type,&L,&R);
if (type==3)
printf("%lld\n",query(1,1,n,L,R));
else {
scanf("%lld",&c);
update(1,1,n,L,R,c%mod,type);
}
}
return 0;
}