• 线段树(每段相加,每段相乘,查询)


    题目分析

    看题面可以知道题目的要求:

    对于一个长度为N的序列a支持以下操作

    1.令所有满足l<=i<=r的ai全部变为ai*c。

    2.令所有满足l<=i<=r的ai全部变为ai+c。

    3.求所有满足l<=i<=r的ai的和。

    显然这是对一个区间做加法和乘法的操作,可以使用线段树完成。

    联想只有区间加法的过程,对于线段树上的一个节点,我们设sum表示该区间的和,inc表示该区间每个数要加上的数,那么该节点所表示的区间和为sum + inc * (r - l + 1)

    属于x+bx+b这种形式,(r - l + 1)(rl+1)可以看作常数。

    但是现在区间不仅有加法,还有乘法,因此很容易想到区间和的形式应该为:ax+bax+b

    表示现在的区间和是原来的区间和先乘以a再加上b。

    在程序中我们把mtp定义为a,sum定义为x,inc定义为b,下传标记时节点的更新就是sum = mtp * sum + inc

    区间修改

    当我们要修改一个区间时,要保证ax+b的形式,即先乘后加的形式。当将区间乘以一个数k时,原来的区间和为ax+bax+b,乘以k得k(ax+b)=kax+kbk(ax+b)=kax+kb,也就是把节点的inc和mtp都乘上一个k。

    区间加一个数更加简单,原来的区间和为ax+bax+b,加上一个k为ax+b+kax+b+k,合并b, k得ax+(b+k)ax+(b+k),也就是把原来的inc加上一个k。

    标记下传

    我们设要下传标记的节点的inc为bb,sum为xx,mtp为aa,因此这个节点的和为ax+bax+b,它的一个儿子的inc为b'b′,sum为yy,mtp为a'a′,这个节点的和为a'y+b'ay+b′,为了保持先乘后加的顺序,先把该节点的和乘以aa得aa'y+ab'aay+ab′然后加上b得aa'y+ab'+baay+ab+b合并一下得(aa')y+(ab'+b)(aa)y+(ab+b)也就是把这个节点的儿子的mtp乘以这个节点的mtp,然后把这个节点的儿子的inc乘以这个节点的mtp再加上这个节点的inc,更新这个节点,清空这个节点的标记,然后标记就下传完毕了。

    #include<stdio.h>
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define ll long long
    const int manx = 100011;
    ll sum[manx<<2],la[manx<<2],n,p;
    void PushUP(int rt)
    {
        sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    }
    void build(int l,int r,int rt)
    {
        la[rt]=0;
        if(l==r)
        {
            scanf("%lld",&sum[rt]);
            return ;
        }
        int m = (l+r) >> 1;
        build(lson);
        build(rson);
        PushUP(rt);
    }
    void PushDown(int rt,int m)
    {
        if(la[rt])
        {
            la[rt<<1]+=la[rt];
            la[rt<<1|1]+=la[rt];
            sum[rt<<1]+=la[rt]*(m-(m>>1));
            sum[rt<<1|1]+=la[rt]*(m>>1);
            la[rt]=0;
        }
    }
    void update(int L,int R,int c,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            la[rt]+=c;
            sum[rt]+=(ll)c*(r-l+1);
            return ;
        }
        PushDown(rt,r-l+1);
        int m=(l+r)>>1;
        if(L<=m)
        update(L,R,c,lson);
        if(R>m)
        update(L,R,c,rson);
        PushUP(rt);
    }
    
    ll query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R)
        {
            return sum[rt];
        }
        PushDown(rt,r-l+1);
        ll res=0;
        int m=(l+r)>>1;
        if(L<=m)
        res+=query(L,R,lson);
        if(R>m)
        res+=query(L,R,rson);
        return res;
    }
    
    int main( )
    {   
        scanf("%lld%lld",&n,&p);
        build(1,n,1);
        scanf("%d",&m);
        while(m--)
        {
            int op;
            scanf("%d",&op);
            if(op==1)
            {
                
            }
            else if(op==2)
            {
                scanf("%d%d%d",&l,&r,&c);
                update(l,r,c,1,n,1);
            }
                
        }
    }
  • 相关阅读:
    C++利用SOAP开发WebService
    C++中使用soap toolkit访问webService详解
    第一次课堂作业之Circle
    第四次作业(计算器第二步)
    第三次作业之Calculator项目随笔
    C++视频课程小结(3)
    C++视频课程小结(2)
    C++视频课程小结(1)
    第二次作业之视频课程题
    第二次作业之编程题
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9600531.html
Copyright © 2020-2023  润新知