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

Posted Capella

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「模板」 线段树——区间乘 && 区间加 && 区间求和相关的知识,希望对你有一定的参考价值。

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

<题目链接>


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

#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;
}

谢谢阅读。

以上是关于「模板」 线段树——区间乘 && 区间加 && 区间求和的主要内容,如果未能解决你的问题,请参考以下文章

luogu P3372ybtoj线段树课堂过关例题2区间查改 &模板线段树 1

P3373 模板线段树 2区间乘/加 区间查询

自用综合线段树模板(区间加乘区间置数区间求和)

P3373 模板线段树 2 区间求和 区间乘 区间加

Luogu 3373 - 模板线段树 2 - [加乘线段树]

[模板]洛谷T3373 线段树 模板2