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 <stdio.h>
#include <string.h>

struct node
{
    long long left, right, lazy;
    long long data;
}tree[4000055];
long long a[1000055];

void build(long long l,long long r, long long k)    //普通方法建樹即可
{
    tree[k].left = l;
    tree[k].right = r;
    tree[k].lazy = 0;
    if(l==r)
    {
        tree[k].data = a[l];
        return;
    }
    else
    {
        long long mid = (l + r) / 2;
        build(l, mid, 2 * k);
        build(mid+1, r, 2 * k + 1);
        tree[k].data = tree[2 * k].data + tree[2 * k + 1].data;
    }
}

void pushdown(long long k)     //把節點k的lazy值傳給他的孩子,有需要時向下更新
{
    tree[2 * k].lazy += tree[k].lazy;
    tree[2 * k + 1].lazy += tree[k].lazy;
    tree[2 * k].data += (tree[2 * k].right - tree[2 * k].left + 1) * tree[k].lazy;
    tree[2 * k + 1].data += (tree[2 * k + 1].right - tree[2 * k + 1].left + 1) * tree[k].lazy;
    tree[k].lazy = 0;
}

long long ask(long long x, long long y, long long k)
{
    if(tree[k].lazy != 0) pushdown(k);      //看到節點,向下更新,
                      //否則如果走下面else的話,節點k的lazy傳不到下面的小區間
    if(x <= tree[k].left && tree[k].right <= y) return tree[k].data;
    else
    {
        long long mid = (tree[k].left + tree[k].right) / 2;
        if(y <= mid) return ask(x, y, 2 * k);
        else if(x > mid) return ask(x, y, 2 * k + 1);
        else return ask(x, y, 2 * k) + ask(x, y, 2 * k + 1);
    }
}

void add(long long x, long long y, long long z, long long k)
{
    if(x <= tree[k].left && tree[k].right <= y)
    {
        tree[k].data += (tree[k].right - tree[k].left + 1) * z;        //data不要忘記乘區間元素個數
        tree[k].lazy += z;
        return;
    }
    else
    {
        if(tree[k].lazy != 0) pushdown(k);         //這裏必須要pushdown的,不加會WA
                                        //只要看到新的區間,就pushdown一下好了,更新也沒什麼大壞處
        long long mid = (tree[k].left + tree[k].right) / 2;
        if(y <= mid) add(x, y, z, 2*k);
        else if(x > mid) add(x, y, z, 2*k+1);
        else
        {
            add(x, y, z, 2*k);
            add(x, y, z, 2*k+1);
        }
        tree[k].data = tree[2*k].data + tree[2*k+1].data;   //下面的節點更新完成,上面的自然要變
    }
}

int main()
{
    long long n, m, i, x, y, z;
    char c[10];
    scanf("%lld %lld", &n, &m);
    for(i=1;i<=n;i++)
    {
        scanf("%lld", &a[i]);
    }
    build(1, n, 1);
    while(m--)
    {
        scanf(" %s", c);
        if(c[0]=='Q')
        {
            scanf("%lld %lld", &x, &y);
            printf("%lld\n", ask(x, y, 1));
        }
        else if(c[0]=='C')
        {
            scanf("%lld %lld %lld", &x, &y, &z);
            add(x, y, z, 1);
        }
    }
    return 0;
}

WA了十多遍,
原因是一開始在判斷是否要向下pushdown的時候寫成了if(str[k].lazy>0),
當需要區間減小的時候進不去就WA了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章