bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树
这道题就是线段树 先传乘法标记再传加法
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=400010; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } LL n,m,mod,L,R; struct node{ int l,r; LL sum,add,mt; }tr[M]; void up(int x){tr[x].sum=(tr[x<<1].sum+tr[x<<1^1].sum)%mod;} void cal(LL x,LL mt,LL w){ if(!x) return ; LL l=tr[x].r-tr[x].l+1; tr[x].sum=(tr[x].sum*mt+w*l)%mod; tr[x].add=(tr[x].add*mt+w)%mod; tr[x].mt=tr[x].mt*mt%mod; } void down(LL x){ if(tr[x].add||tr[x].mt!=1){ cal(x<<1,tr[x].mt,tr[x].add); cal(x<<1^1,tr[x].mt,tr[x].add); tr[x].add=0; tr[x].mt=1; } } void build(LL x,LL l,LL r){ tr[x].l=l; tr[x].r=r; tr[x].mt=1; if(l==r){tr[x].sum=read(); return ;} int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1^1,mid+1,r); up(x); } void push_mm(LL x,LL w){ if(L<=tr[x].l&&tr[x].r<=R){cal(x,w,0); return ;} int mid=(tr[x].l+tr[x].r)>>1; down(x); if(L<=mid) push_mm(x<<1,w); if(R>mid) push_mm(x<<1^1,w); up(x); } void push_add(LL x,LL w){ if(L<=tr[x].l&&tr[x].r<=R){cal(x,1,w); return ;} int mid=(tr[x].l+tr[x].r)>>1; down(x); if(L<=mid) push_add(x<<1,w); if(R>mid) push_add(x<<1^1,w); up(x); } LL push_sum(LL x){ if(L<=tr[x].l&&tr[x].r<=R) return tr[x].sum; int mid=(tr[x].l+tr[x].r)>>1; down(x); LL ans=0; if(L<=mid) ans=(ans+push_sum(x<<1))%mod; if(R>mid) ans=(ans+push_sum(x<<1^1))%mod; return ans; } int main() { LL k,w; n=read(); mod=read(); build(1,1,n); m=read(); for(int i=1;i<=m;i++){ k=read(); L=read(); R=read(); if(k==1) w=read(),push_mm(1,w); if(k==2) w=read(),push_add(1,w); if(k==3) printf("%lld\n",push_sum(1)%mod); } return 0; }