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

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

时间:2018-05-29 00:15:37      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:ref   modify   求和   class   线段   big   pushd   private   har   

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

<题目链接>


原来的代码太恶心了,重贴一遍。

#include <cstdio>
int n,m;
long long p;
class SegmentTree
{
    private:
        struct Node
        {
            int l,r;
            long long v,mul,add;
            Node *c[2];
            Node(int l,int r):l(l),r(r),mul(1LL),add(0LL)
            {
                c[0]=c[1]=nullptr;
            }
            ~Node(void)
            {
                if(c[0]!=nullptr)
                    delete c[0];
                if(c[1]!=nullptr)
                    delete c[1];
            }
            long long Size(void)
            {
                return (long long)(r-l+1);
            }
            long long Value(bool p)
            {
                return c[p]!=nullptr ? c[p]->v : 0;
            }
            void Modify(long long _mul,long long _add)
            {
                v=(v*_mul+Size()*_add)%p;
                mul=mul*_mul%p;
                add=(add*_mul+_add)%p;
            }
            void MulModify(long long k)
            {
                v=v*k%p;
                mul=mul*k%p;
                add=add*k%p;
            }
            void AddModify(long long k)
            {
                v=(v+Size()*k)%p;
                add=(add+k)%p;
            }
            void PushUp(void)
            {
                v=(Value(0)+Value(1))%p;
            }
            void PushDown(void)
            {
                if(c[0]!=nullptr)
                    c[0]->Modify(mul,add);
                if(c[1]!=nullptr)
                    c[1]->Modify(mul,add);
                mul=1,add=0;
            }
        }*rt;
        void Build(Node* &i,int l,int r)
        {
            i=new Node(l,r);
            if(l==r)
            {
                scanf("%lld",&i->v);
                return;
            }
            int mid=l+r>>1;
            Build(i->c[0],l,mid);
            Build(i->c[1],mid+1,r);
            i->PushUp();
        }
        void Mul(Node* i,int l,int r,long long k)
        {
            if(l==i->l && r==i->r)
            {
                i->MulModify(k);
                return;
            }
            i->PushDown();
            int mid=i->l+i->r>>1;
            if(r<=mid)
                Mul(i->c[0],l,r,k);
            else if(l>mid)
                Mul(i->c[1],l,r,k);
            else
            {
                Mul(i->c[0],l,mid,k);
                Mul(i->c[1],mid+1,r,k);
            }
            i->PushUp();
        }
        void Add(Node* i,int l,int r,long long k)
        {
            if(l==i->l && r==i->r)
            {
                i->AddModify(k);
                return;
            }
            i->PushDown();
            int mid=i->l+i->r>>1;
            if(r<=mid)
                Add(i->c[0],l,r,k);
            else if(l>mid)
                Add(i->c[1],l,r,k);
            else
            {
                Add(i->c[0],l,mid,k);
                Add(i->c[1],mid+1,r,k);
            }
            i->PushUp();
        }
        long long Sum(Node* i,int l,int r)
        {
            if(l==i->l && r==i->r)
                return i->v;
            i->PushDown();
            int mid=i->l+i->r>>1;
            if(r<=mid)
                return Sum(i->c[0],l,r);
            else if(l>mid)
                return Sum(i->c[1],l,r);
            else
                return (Sum(i->c[0],l,mid)+Sum(i->c[1],mid+1,r))%p;
        }
    public:
        SegmentTree(int n):rt(nullptr)
        {
            Build(rt,1,n);
        }
        ~SegmentTree(void)
        {
            delete rt;
        }
        void Mul(int l,int r)
        {
            long long k;
            scanf("%lld",&k);
            Mul(rt,l,r,k);
        }
        void Add(int l,int r)
        {
            long long k;
            scanf("%lld",&k);
            Add(rt,l,r,k);
        }
        void Sum(int l,int r)
        {
            printf("%lld\n",Sum(rt,l,r));
        }
};
int main(int argc,char** argv)
{
    scanf("%d %d %lld",&n,&m,&p);
    static SegmentTree *T=new SegmentTree(n);
    for(int i=1,opt,x,y;i<=m;++i)
    {
        scanf("%d %d %d",&opt,&x,&y);
        switch(opt)
        {
            case 1:
                T->Mul(x,y);
                break;
            case 2:
                T->Add(x,y);
                break;
            case 3:
                T->Sum(x,y);
                break;
        }
    }
    delete T;
    return 0;
}

谢谢阅读。

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

标签:ref   modify   求和   class   线段   big   pushd   private   har   

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

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