题目链接:http://codevs.cn/problem/1082/
时间限制: 3 s 空间限制: 128000 KB

题目描述 Description

给你N个数,有两种操作:
1:给区间[a,b]的所有数增加X
2:询问区间[a,b]的数的和。

输入描述 Input Description

第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,每行表示操作的个数,如果第一个数是1,后接3个正整数,表示在区间[a,b]内每个数增加X,如果是2,表示操作2询问区间[a,b]的和是多少。
pascal选手请不要使用readln读入

输出描述 Output Description

对于每个询问输出一行一个答案。

样例输入 Sample Input

3
1
2
3
2
1 2 3 2
2 2 3

样例输出 Sample Output

9

数据范围及提示 Data Size & Hint

数据范围

1<=n<=200000
1<=q<=200000

解题思路

树状数组模板,区间更新,区间查询。

#include <bits/stdc++.h>
using namespace std;
long long bits_0[200005], bits_1[200005], n;
int lowbit(int x) {
    return x & -x;
}
void Update(long long *bits, int i, long long k) {
    while (i <= n) {
        bits[i] += k;
        i += lowbit(i);
    }
}
long long PrefixSum(long long *bits, int i) {
    long long ans = 0;
    while (i > 0) {
        ans += bits[i];
        i -= lowbit(i);
    }
    return ans;
}
long long RangeSum(int left, int right) {
    long long ans = PrefixSum(bits_0, right) * right + PrefixSum(bits_1, right);
    return ans - PrefixSum(bits_0, left - 1) * (left - 1) - PrefixSum(bits_1, left - 1);
}
int main() {
    int q, del, judge, delta, left, right;
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &delta);
        Update(bits_1, i, delta);
    }
    scanf("%d", &q);
    while (q--) {
        scanf("%d", &judge);
        if (judge - 1) {
            scanf("%d%d", &left, &right);
            printf("%lld\n", RangeSum(left, right));
        }
        else {
            scanf("%d%d%d", &left, &right, &delta);
            Update(bits_0, left, delta);
            Update(bits_0, right + 1, -delta);
            Update(bits_1, left, 1ll * -delta * (left - 1));
            Update(bits_1, right + 1, 1ll * delta * right);
        }
    }
    return 0;
}