码迷,mamicode.com
首页 > 其他好文 > 详细

线段树模板——区间乘 && 区间加 && 区间求和

时间:2018-02-23 19:00:37      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:cas   模板   cpp   int   print   www.   void   bre   show   

线段树模板——区间乘 && 区间加 && 区间求和

<题目链接>


来自一个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;
}

谢谢阅读。

线段树模板——区间乘 && 区间加 && 区间求和

标签:cas   模板   cpp   int   print   www.   void   bre   show   

原文地址:https://www.cnblogs.com/Capella/p/8462769.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!