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

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

<题目链接>



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

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

谢谢阅读。

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

时间: 2024-08-02 12:23:59

「模板」 线段树——区间乘 && 区间加 && 区间求和的相关文章

「模板」线段树静态开点(单点+区间修改)、动态开点

相关讲解资料: 树状数组:https://blog.csdn.net/qq_34374664/article/details/52787481 (线段树预备) 线段树讲解: 初学版:https://blog.csdn.net/zearot/article/details/52280189 进阶完整版:https://www.cnblogs.com/AC-King/p/7789013.html 代码: 完整注释模板一张,参(chao)考(xi)楼上的博客 #include<iostream> #

poj 3468 A Simple Problem with Integers (线段树 成段更新 加值 求和)

题目链接 题意: 只有这两种操作 C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000."Q a b" means querying the sum of Aa, Aa+1, ... , Ab. 分析:自己写的有点麻烦了,写的时候手残+脑残,改了好久. val+lazy*(r-l+1)表示和,如果lazy==0表示当前区间加的值不统一. 1 #include <iostream

「ZJOI2019」线段树

传送门 Description 线段树的核心是懒标记,下面是一个带懒标记的线段树的伪代码,其中 tag 数组为懒标记: 其中函数\(Lson(Node)\)表示\(Node\)的左儿子,\(Rson(Node)\)表示\(Node\)的右儿子. 有一棵 \([1,n]\)上的线段树,编号为\(1\) .初始时什么标记都没有. 每次修改会把当前所有的线段树复制一份,然后对于这些线段树实行一次区间修改操作. 每次修改后线段树棵数翻倍,第 \(i\)次修改后,线段树共有 \(2^i\) 棵. 每次询问

线段树 --- (单点更新、求区间最值、模板题)

A - 敌兵布阵 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营 地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工 兵营地的人数都有可能发生

「模板」 树套树

「模板」 树套树 <题目链接> 线段树套 SBT. 有生以来写过的最长代码. 虽然能过,但我删除 SBT 点的时候没回收内存!写了就 RE! 先放上来吧,回收内存调出来了再修改qwq. #include <algorithm> #include <climits> #include <cstdio> using std::max; using std::min; const int MAXN=50010; int n,m; class SegmentTree

HDU 1754 I Hate It(线段树之单点更新,区间最值)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 70863    Accepted Submission(s): 27424 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的

Bzoj 3050: [Usaco2013 Jan]Seating(线段树裸题,然而区间修改标记下放和讨论Push_up很揪心)

题目链接 题意:开始有一个空白的区间,每次可能进行两个操作:A 将一个长度为p的区间加入一段连续空白的位置 L:一个区间恢复空白:要求出A不能进行的次数. 非常裸的线段树题目,用线段树统计最大的空白区间,每个节点需要记录当前区间的最长空白区间,从左端开始的最长空白区间,从右端开始的最长空白区间.Push_up的时候要讨论下,可以分别取[l,mid]和[mid+1,r]的最大空白区间,也可以用[l,mid]的从右端开始的最长空白区间+[mid+1,r]从左端开始的最大空白区间. 每次A的时候,就查

NYOJ 1068 ST(线段树之 成段更新+区间求和)

ST 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描述 "麻雀"lengdan用随机数生成了后台数据,但是笨笨的他被妹纸的问题给难住了... 已知lengdan生成了N(1=<N<=10005)个随机整数,妹子对这些数可能有以下几种操作或询问: 1,A a b c 表示给区间a到b内每个数都加上c: 2,S a b  表示输出区间a到b内的和: 3,Q a b 表示区间a到b内的奇数的个数: 为了使妹纸不口渴,所以我们决定妹纸的询问次数少一点,即

HDU 1754-I Hate It(线段树:单点更新,区间最值)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 39163    Accepted Submission(s): 15507 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师