poj 3468 A Simple Problem with Integers(线段树)

题目链接:http://poj.org/problem?id=3468

思路分析:使用sumv[i]记录一段线段区间的目前的sum,addv[i]记录在整个过程中对某一段线段区间上的所有增加值的和;

更新操作:将需要更新的区间分为多段不相交的区间,并在这些区间上更新该区间上增加的值,并修改这些区间的sum值以及其父节点的sum值;

查询操作:使用全局变量sum_ans,将查询的区间分为多段不相交的区间,并且进行增加的值的传递,将增加的值传给子节点,将这些区间的值

加上传递的增加的值即为所求;

 

代码如下:

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

const int MAX_N = 2 * 1000000 + 100;
long long sumv[MAX_N], addv[MAX_N];
long long sum_ans, arr[MAX_N];

void Build(int root, int l, int r, long long arr[])
{
    if (l == r)
    {
        addv[root] = arr[l];
        sumv[root] = arr[l];
    }
    else
    {
        int mid = (l + r) / 2;

        Build(2 * root, l, mid, arr);
        Build(2 * root + 1, mid + 1, r, arr);
        sumv[root] = sumv[2 * root] + sumv[2 * root + 1];
    }
}

void Updata(int o, int l, int r, long long add_value, int ql, int qr)
{
    if (l > qr || r < ql)
        return;
    if (ql <= l && r <= qr)
        addv[o] += add_value;
    else
    {
        int mid = (l + r) / 2;

        Updata(2 * o, l, mid, add_value, ql, qr);
        Updata(2 * o + 1, mid + 1, r, add_value, ql, qr);
    }

    sumv[o] = 0;
    if (l < r)
        sumv[o] = sumv[2 * o] + sumv[2 * o + 1];
    sumv[o] += addv[o] * (r - l + 1);
}

void Query(int o, int l, int r, int ql, int qr, long long add)
{
    if (l > qr || r < ql)
        return;
    if (ql <= l && r <= qr)
        sum_ans += sumv[o] + add * (r - l + 1);
    else
    {
        int mid = (l + r) / 2;

        Query(2 * o, l, mid, ql, qr, add + addv[o]);
        Query(2 * o + 1, mid + 1, r, ql, qr, add + addv[o]);
    }
}

int main()
{
    int num, query_times;

    scanf("%d %d", &num, &query_times);
    for (int i = 1; i <= num; ++i)
        scanf("%lld", &arr[i]);
    Build(1, 1, num, arr);

    for (int i = 0; i < query_times; ++i)
    {
        char str[2];
        int ql, qr, add_value;

        scanf("%s", str);
        if (str[0] == 'Q')
        {
            sum_ans = 0;
            scanf("%d %d", &ql, &qr);
            Query(1, 1, num, ql, qr, 0);
            printf("%lld\n", sum_ans);
        }
        else
        {
            scanf("%d %d %d", &ql, &qr, &add_value);
            Updata(1, 1, num, add_value, ql, qr);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/tallisHe/p/4564940.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值