POJ 3468 A Simple Problem with Integers (区间加区间查找)

You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"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.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.
#include <cstdio>
#include <iostream>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
using namespace std;

#define ll long long
#define eps 1e-9

const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;

ll n, q, x, y, k, ans, a[1000000+8];///开ll,不然数据太大,加起来会爆int
char c;

struct node
{
    int l, r;
    ll sum, plz;///开ll,不然数据太大,加起来会爆int
}tree[4*1000000+8];

void build(int i, ll l, ll r)
{
    tree[i].l = l;
    tree[i].r = r;
    tree[i].plz = 0;
    if(l == r)///如果已经是叶子结点
        tree[i].sum = a[l];
    else
    {
        ll mid = (l+r)/2;
        build(i*2, l, mid);///往左儿子进行建树
        build(i*2+1, mid+1, r);///往右儿子进行建树
        tree[i].sum = tree[i*2].sum+tree[i*2+1].sum;///父节点的和等于左儿子的和加右儿子的和
    }
}

void push_down(int i)///把自己的lazytage归零,并给自己的儿子加上,并让自己的儿子加上k*(r-l+1)
{
    tree[i*2].plz += tree[i].plz;///左儿子的加标记等于父节点的加标记
    tree[i*2+1].plz += tree[i].plz;///右儿子的加标记等于父节点的加标记
    tree[i*2].sum += tree[i].plz*(tree[i*2].r-tree[i*2].l+1);///(左儿子的和)=(左儿子的和)+(左儿子所控制的元素个数)*父节点的加标记
    tree[i*2+1].sum += tree[i].plz*(tree[i*2+1].r-tree[i*2+1].l+1);///(右儿子的和)=(右儿子的和)+(右儿子所控制的元素个数)*父节点的加标记
    tree[i].plz = 0;///父节点标记归零
}

void pls(int i, ll l, ll r, ll k)///区间加
{
    if(tree[i].r == r && tree[i].l == l)///如果这个区间恰好是要查找的区间
    {
        tree[i].plz += k;///加标记加上k,表示该区间已经在原来的基础上加了那么多东西
        tree[i].sum += k*(r-l+1);///(这个区间的和)=(这个区间的和)+(要加的数)*(这个区间所控制元素的个数)
        return;
    }
    if(tree[i].l == tree[i].r)///如果为叶子结点,就直接返回他的值
        return;
    push_down(i);///把自己的lazytage归零,并给自己的儿子加上,并让自己的儿子加上k*(r-l+1)
    ll mid = (tree[i].l+tree[i].r)/2;
    if(mid >= r)///如果这个点中间的值大于右边的区间,就往左儿子那边搜索
        pls(i*2, l, r, k);
    else if(mid < l)///如果这个点中间的值小于左边的区间,就往右儿子那边搜索
        pls(i*2+1, l, r, k);
    else///否则就是左儿子右儿子都包含有这个区间,都搜索
    {
        pls(i*2, l, mid, k);
        pls(i*2+1, mid+1, r, k);
    }
    tree[i].sum = tree[i*2].sum + tree[i*2+1].sum;
}

void search(int i, ll l, ll r)///区间查找
{
    if(tree[i].l >= l && tree[i].r <= r)///如果这个区间在目标区间内
    {
        ans += tree[i].sum;
        return;
    }
    push_down(i);///把自己的lazytage归零,并给自己的儿子加上,并让自己的儿子加上k*(r-l+1)
    ll mid = (tree[i].l+tree[i].r)/2;
    if(l <= mid)
        search(i*2, l, r);///[l, r]区间不能改,因为题目要搜索的就是[l, r]区间
    if(mid<r)
        search(i*2+1, l, r);
}

int main()
{
    scanf("%lld%lld", &n, &q);
    for(int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    build(1, 1, n);
    for(int i = 0; i<q; i++)
    {
        ans = 0;
        getchar();
        scanf("%c", &c);
        getchar();
        if(c == 'C')
        {
            scanf("%lld%lld%lld", &x, &y, &k);
            pls(1, x, y, k);
        }
        else
        {
            scanf("%lld%lld", &x, &y);
            search(1, x, y);
            printf("%lld\n", ans);
        }
    }
    return 0;
}

 

posted @ 2019-08-05 19:25  明霞  阅读(142)  评论(0编辑  收藏  举报