1. 程式人生 > >線段樹模板——區間乘 && 區間加 && 區間求和

線段樹模板——區間乘 && 區間加 && 區間求和

markdown 區間求和 www. -m 閱讀 https d+ pre 題目

線段樹模板——區間乘 && 區間加 && 區間求和

<題目鏈接>


來自一個NOIP沒學好的省選選手——本應早在NOIP之前學好的內容。


#include <cstdio>
const int MAXN=100010;
int n,m;
long long p;
class SegmentTree
{
    public:
        void Build(int i,int l,int r)
        {
            s[i]=node(l,r,1LL,0LL);
            if(l==r)
            {
                scanf("
%lld",&s[i].v); return; } int j=i<<1,mid=l+r>>1; Build(j,l,mid),Build(j|1,mid+1,r); PushUp(i); } void Mul(int i,int l,int r,long long k) { if(l==s[i].l && r==s[i].r) { s[i].v=s[i].v*k%p; s[i].mul=s[i].mul*k%p; s[i].add=s[i].add*k%p; return
; } PushDown(i); int j=i<<1,mid=s[i].l+s[i].r>>1; if(r<=mid) Mul(j,l,r,k); else if(l>mid) Mul(j|1,l,r,k); else Mul(j,l,mid,k),Mul(j|1,mid+1,r,k); PushUp(i); } void
Add(int i,int l,int r,long long k) { if(l==s[i].l && r==s[i].r) { s[i].v=(s[i].v+(r-l+1)*k)%p; s[i].add=(s[i].add+k)%p; return; } PushDown(i); int j=i<<1,mid=s[i].l+s[i].r>>1; if(r<=mid) Add(j,l,r,k); else if(l>mid) Add(j|1,l,r,k); else Add(j,l,mid,k),Add(j|1,mid+1,r,k); PushUp(i); } long long Sum(int i,int l,int r) { if(l==s[i].l && r==s[i].r) return s[i].v; PushDown(i); int j=i<<1,mid=s[i].l+s[i].r>>1; if(r<=mid) return Sum(j,l,r); else if(l>mid) return Sum(j|1,l,r); else return (Sum(j,l,mid)+Sum(j|1,mid+1,r))%p; } private: struct node { int l,r; long long v,mul,add; node(int _l=0,int _r=0,long long _mul=0,long long _add=0) { l=_l,r=_r,mul=_mul,add=_add; } }s[MAXN<<2]; void Update(int i,long long mul,long long add) { s[i].v=(s[i].v*mul+(s[i].r-s[i].l+1)*add)%p; s[i].mul=s[i].mul*mul%p; s[i].add=(s[i].add*mul+add)%p; } void PushUp(int i) { int j=i<<1; s[i].v=(s[j].v+s[j|1].v)%p; } void PushDown(int i) { int j=i<<1; Update(j,s[i].mul,s[i].add),Update(j|1,s[i].mul,s[i].add); s[i].mul=1,s[i].add=0; } }T; int main(int argc,char *argv[]) { scanf("%d %d %lld",&n,&m,&p); T.Build(1,1,n); for(int i=1,opt,x,y;i<=m;++i) { long long k; scanf("%d %d %d",&opt,&x,&y); switch(opt) { case 1: scanf("%lld",&k); T.Mul(1,x,y,k); break; case 2: scanf("%lld",&k); T.Add(1,x,y,k); break; case 3: printf("%lld\n",T.Sum(1,x,y)); break; } } return 0; }

謝謝閱讀。

線段樹模板——區間乘 && 區間加 && 區間求和