【树状数组】【模板3】区间修改,区间查询

Description

You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of op
eration 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.
1.给[a ,b]整体上加上一个常数c。 
2.查询[a ,b]区间的和。 

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. The sums may exceed the range of 32-bit integers

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

分析

利用模板2里的差分数组,我们可以快速地修改区间。

那么在使用差分数组的情况下如何快速查询区间值呢?

我们来推导一个式子

首先,查询区间值其实就是查询区间内的每一个元素,而在我们的差分数组中每个元素等于对应的前缀和

所以我们需要求的区间值就变成了差分数组前若干个前缀和之和

写出来就是这样

a[1] + (a[1] + a[2]) + (a[1] + a[2] + a[3]) + ...

我们进行一下变形(这步要看懂)

k * (a[1] + a[2] + ...) - (0 * a[1] + 1 * a[2] + ...)

通过观察我们可以发现后面那一堆其实都是(i - 1) *  a[ i ]

写成求和符号

k * \sum_{i = 1}^{k}a[i] - \sum_{i = 1}^{k}(i - 1) * a[i]

那么这道题就很清晰了

我们只需要再使用一个树状数组存下(i - 1) *  a[ i ]就可以快速计算后面那一坨

\sum_{j = l}^ {r} \sum_{i = l} ^ {j}tree[i]

然后就可以算出区间值了

代码

#include
#include
using namespace std;
 
long long n, q;
long long a[100010];
long long tree1[100010];
long long tree2[100010];
 
inline long long read() {
    long long x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
    return x * f;
}
 
long long ask(long long *tree, long long x) {
    long long sum = 0;
    for (; x; x -= (x & -x)) sum += tree[x];
    return sum;
}
 
void add(long long *tree, long long x, long long y) {
    for (; x <= n; x += (x & -x)) tree[x] += y;
}
 
 
int main() {
    n = read(), q = read();
    for (long long i = 1; i <= n; i++) a[i] = a[i - 1] + read();
    while (q--) {
        char c;
        cin >> c;
        if (c == 'C') {
            long long l = read(), r = read(), x = read();
            add(tree1, l, x);
            add(tree1, r + 1, -x);
            add(tree2, l, l * x);
            add(tree2, r + 1, -(r + 1) * x);
        }
        else {
            long long l = read(), r = read(), ans = 0;
            ans = (a[r] + (r + 1) * ask(tree1, r) - ask(tree2, r)) - (a[l - 1] + l * ask(tree1, l - 1) - ask(tree2, l - 1));
            printf("%lld\n", ans);
        }
    }
}
 

 

你可能感兴趣的:(数据结构)