欢迎访问~原文出处——博客园-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 ",query(1,1,n,L,R)); else { scanf("%lld",&c); update(1,1,n,L,R,c%mod,type); } } return 0; }