poj3468

题意:一个数列,每次操作可以是将某区间数字都加上一个相同的整数,也可以是询问一个区间中所有数字的和。(这里区间指的是数列中连续的若干个数)对每次询问给出结果。

分析:线保留型线段树,线段树中每个节点有两个变量:增量与和,一个记录当前节点对应区间被整体增加了几,另一个记录该区间的真子区间被增加了之后的和是多少。(该区间数字当前和=和+增量×区间长度)

修改时更新路线上不完整覆盖的节点的和变量以及恰好完整覆盖的节点的增量变量。询问可以通过回溯过程通过各节点两变量值求得。

 

三种线段树,参见:http://www.cnblogs.com/rainydays/archive/2011/09/06/2169082.html

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;

const    int        maxn = 100001;

struct cnode
{
    int        l, r;
    long long nsum, inc;
    cnode    *pleft, *pright;
};

int        n, q, ncount;
cnode    tree[maxn * 3];

void buildtree(cnode *proot, int s, int e)
{
    proot->l = s;
    proot->r = e;
    proot->inc = 0;
    proot->nsum = 0;
    if (s != e)
    {
        ncount++;
        proot->pleft = tree + ncount;
        ncount++;
        proot->pright = tree + ncount;
        buildtree(proot->pleft, s, (s + e) / 2);
        buildtree(proot->pright, (s + e) / 2 + 1, e);
    }
}

void insert(cnode *proot, int s, int e, long long increase)
{
    int        mid;

    if (s > proot->r || e < proot->l)
        return;
    s = max(s, proot->l);
    e = min(e, proot->r);
    mid = (proot->l + proot->r) / 2;
    if (s == proot->l && e == proot->r)
    {
        proot->inc += increase;
        return;
    }
    proot->nsum += (e - s + 1) * increase;
    insert(proot->pleft, s, e, increase);
    insert(proot->pright, s, e, increase);
}

long long query(cnode *proot, int s, int e)
{
    int        mid;

    if (s > proot->r || e < proot->l)
        return 0;
    s = max(s, proot->l);
    e = min(e, proot->r);
    mid = (proot->l + proot->r) / 2;
    if (proot->l == s && proot->r == e)
        return proot->nsum + proot->inc * (proot->r - proot->l + 1);
    long long inc_value = proot->inc * (e - s + 1);
    return query(proot->pleft, s, e) + query(proot->pright, s, e) + inc_value;
}

int main()
{
    int        i, h, s, e;
    char    ch;

    scanf("%d%d", &n, &q);
    ncount = 0;
    buildtree(tree, 1, n);
    for (i = 0; i < n; i++)
    {
        scanf("%d", &h);
        insert(tree, i + 1, i + 1, h);
    }
    for (i = 0; i < q; i++)
    {
        getchar();
        scanf("%c", &ch);
        if (ch == 'C')
        {
            scanf("%d%d%d", &s, &e, &h);
            insert(tree, s, e, h);
        }
        else
        {
            scanf("%d%d", &s, &e);
            printf("%lld\n", query(tree, s, e));
        }
    }
    return 0;
}
View Code

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值