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

题目分析

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

对于一个长度为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);
        }
            
    }
}

 

posted @ 2018-09-06 19:54  shuai_hui  阅读(490)  评论(0编辑  收藏  举报