这个板子不打就是手生……一段时间不会处理线段树了qwq,这个题难点就是在于下放标记
#include<iostream> #include<cstring> #include<cstdio> using namespace std; typedef long long lo; lo n,p,m,a[100010],x,y,z,fl,qwq; struct in {lo l,r,s,f1,f2; }ter[400040]; inline void re(lo &c) {c=0;char b=getchar();while(b<'0'||b>'9')b=getchar();while(b>='0'&&b<='9')c=c*10+b-'0',b=getchar(); } inline void u(lo w) {ter[w].s=((ter[w<<1].s%p)+(ter[w<<1|1].s%p))%p; } inline void build(lo l,lo r,lo w) {ter[w]=(in){l,r,0,1,0};if(l==r){ter[w].s=a[l];return;}lo mid=l+r>>1;build(l,mid,w<<1),build(mid+1,r,w<<1|1);u(w); } inline void d(lo w) {lo f1=ter[w].f1,f2=ter[w].f2;if(f1==1&&f2==0)return;ter[w<<1].f1*=f1,ter[w<<1].f1%=p;//不管加法还是乘法的flag都要乘上他们父亲的乘法flag ter[w<<1|1].f1*=f1,ter[w<<1|1].f1%=p;ter[w<<1].f2*=f1,ter[w<<1].f2%=p;ter[w<<1|1].f2*=f1,ter[w<<1|1].f2%=p;ter[w<<1].f2+=f2,ter[w<<1].f2%=p;//加法还要加上 ter[w<<1|1].f2+=f2,ter[w<<1|1].f2%=p;ter[w<<1].s*=f1,ter[w<<1].s%=p;//先乘再加 ter[w<<1|1].s*=f1,ter[w<<1|1].s%=p;ter[w<<1].s+=f2*(ter[w<<1].r-ter[w<<1].l+1),ter[w<<1].s%=p;ter[w<<1|1].s+=f2*(ter[w<<1|1].r-ter[w<<1|1].l+1),ter[w<<1|1].s%=p;ter[w].f1=1,ter[w].f2=0;//乘法的flag赋为1是因为最起码*1,不能*0 } void cha1(lo l,lo r,lo jia,lo w) {if(ter[w].l==l&&ter[w].r==r)//乘法是一起乘 {ter[w].f1*=jia,ter[w].f1%=p;ter[w].f2*=jia,ter[w].f2%=p;ter[w].s*=jia,ter[w].s%=p;return;}d(w);lo mid=ter[w].l+ter[w].r>>1;if(r<=mid)cha1(l,r,jia,w<<1);else if(l>mid)cha1(l,r,jia,w<<1|1);elsecha1(l,mid,jia,w<<1),cha1(mid+1,r,jia,w<<1|1);u(w); } void cha2(lo l,lo r,lo jia,lo w) {if(ter[w].l==l&&ter[w].r==r)//加法是单独加在加法的flag上 {ter[w].f2+=jia,ter[w].f2%=p;ter[w].s+=jia*(ter[w].r-ter[w].l+1),ter[w].s%=p;return;}d(w);lo mid=ter[w].l+ter[w].r>>1;if(r<=mid)cha2(l,r,jia,w<<1);else if(l>mid)cha2(l,r,jia,w<<1|1);elsecha2(l,mid,jia,w<<1),cha2(mid+1,r,jia,w<<1|1);u(w); } lo ask(lo l,lo r,lo w) {if(ter[w].l==l&&ter[w].r==r)return ter[w].s;lo mid=ter[w].l+ter[w].r>>1,re=0;d(w);if(r<=mid)re+=ask(l,r,w<<1)%p;else if(l>mid)re+=ask(l,r,w<<1|1)%p;elsere+=ask(l,mid,w<<1)%p,re+=ask(mid+1,r,w<<1|1)%p;u(w);return re; } int main() {re(n),re(p);for(int i=1;i<=n;i++)re(a[i]);build(1,n,1);//建树 re(m);for(int i=1;i<=m;i++){re(fl),re(x),re(y);if(fl==1)re(z),cha1(x,y,z,1);//区间乘 if(fl==2)re(z),cha2(x,y,z,1);//区间加 if(fl==3)qwq=ask(x,y,1)%p,printf("%lld\n",qwq);//查询 } }