如在阅读本文时遇到不懂的部分,请在评论区询问,或跳转 线段树总介绍
这题多出了一个乘法,显然须要在开一个乘法的tag
此时pushdown——线段树的核心操作就难写了许多
考虑乘法tag的维护
假设当前区间和为v,加法tag为pt , 下传的变化值为 乘法mk
若先乘法后加法
v=v*mk+pt*mk
若先加法后乘法
v=(v+pt)*mk
显然(雾)第二种好写,据说第一种可以写但不好写
那就第二种吧...
乘法tag与加法乘法tag,和v的关系都可以很容易推出
附注:
1. (a+=b)%=p等价于 a+=b,a%=p;同理可以更多括号
2. plus -> 加法 mul ->乘法
代码
/*luogu3373*/ /*多%避免爆栈*/ /*(a+=b)%=p*/ #include<iostream> #include<algorithm> #include<stdio.h> #include<cstring> #include<string> #include<cctype> using namespace std; typedef long long LL; inline LL rd(){ char c=getchar();LL x=0;bool f=true; while(!isdigit(c)){if(c=='-')f=false;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?x:-x; } const LL N=1e7+3; LL n,m,p,a[N]; struct node{LL l,r,v,mt,pt;}t[N<<2]; #define ls (rt<<1) #define rs (rt<<1|1) #define mid (t[rt].l+t[rt].r>>1) #define pushup(rt) (t[rt].v=t[ls].v+t[rs].v)%=p #define len(rt) (t[rt].r-t[rt].l+1) void build(LL rt,LL l,LL r){ t[rt].l=l,t[rt].r=r,t[rt].mt=1,t[rt].pt=0; if(l==r){t[rt].v=a[l]%p;return;} build(ls,l,mid);build(rs,mid+1,r); pushup(rt); } void pushdown(LL rt){ if(t[rt].pt==0&&t[rt].mt==1)return; (t[ls].v*=t[rt].mt)%=p; (t[rs].v*=t[rt].mt)%=p; (t[ls].pt*=t[rt].mt)%=p; (t[rs].pt*=t[rt].mt)%=p; (t[ls].mt*=t[rt].mt)%=p; (t[rs].mt*=t[rt].mt)%=p; (t[ls].v+=t[rt].pt*len(ls))%=p; (t[rs].v+=t[rt].pt*len(rs))%=p; (t[ls].pt+=t[rt].pt)%=p; (t[rs].pt+=t[rt].pt)%=p; t[rt].pt=0,t[rt].mt=1; /*t[ls].v = (t[ls].v*t[rt].mt + t[rt].pt*len(ls)) %p; t[rs].v = (t[rs].v*t[rt].mt + t[rt].pt*len(rs)) %p; t[ls].mt=(t[ls].mt*t[rt].mt)%p; t[rs].mt=(t[rs].mt*t[rt].mt)%p; t[ls].pt=(t[ls].pt*t[rt].mt+t[rt].pt)%p; t[rs].pt=(t[rs].pt*t[rt].mt+t[rt].pt)%p; t[rt].mt=1,t[rt].pt=0;*/ } void upd_M(LL rt,LL x,LL y,LL k){ if(x<=t[rt].l&&y>=t[rt].r){(t[rt].pt*=k)%=p;(t[rt].mt*=k)%=p;(t[rt].v*=k)%=p;return;} pushdown(rt); if(x<=mid)upd_M(ls,x,y,k); if(y>mid)upd_M(rs,x,y,k); pushup(rt); } void upd_P(LL rt,LL x,LL y,LL k){ if(x<=t[rt].l&&y>=t[rt].r){(t[rt].pt+=k)%=p;(t[rt].v+=len(rt)*k)%=p;return;} pushdown(rt); if(x<=mid)upd_P(ls,x,y,k); if(y>mid)upd_P(rs,x,y,k); pushup(rt); } LL query(LL rt,LL x,LL y){ if(x<=t[rt].l&&y>=t[rt].r)return t[rt].v%p; LL res=0;pushdown(rt); if(x<=mid)(res+=query(ls,x,y))%=p; if(y>mid)(res+=query(rs,x,y))%=p; return res; } int main(){ n=rd(),m=rd(),p=rd(); for(LL i=1;i<=n;++i)a[i]=rd(); LL ty,x,y,k;build(1,1,n); while(m--){ ty=rd(),x=rd(),y=rd(); switch(ty){ case 1: k=rd(); upd_M(1,x,y,k%p); break; case 2: k=rd(); upd_P(1,x,y,k%p); break; case 3: printf("%lld ",query(1,x,y)%p); } } return 0; }
End