题目链接:https://www.acwing.com/problem/content/244/
1 #include <iostream>
2 #include <cstring>
3 #include <cstdio>
4 #include <algorithm>
5
6 using namespace std;
7
8 typedef long long LL;
9 const int N = 100010;
10 int a[N];
11 LL tr1[N]; //维护b[i]的差分数组
12 LL tr2[N]; //维护 i * b[i] 的差分数组
13 int n, m;
14
15 int lowbit(int x)
16 {
17 return x & -x;
18 }
19
20 int add(LL tr[], int x, LL k)
21 {
22 for (int i = x; i <= n; i += lowbit(i)) tr[i] += k;
23 }
24
25 LL sum(LL tr[], int x)
26 {
27 LL res = 0;
28 for (int i = x; i ; i -= lowbit(i)) res += tr[i];
29 return res;
30 }
31
32 LL per_sum(int x)
33 {
34 return sum(tr1, x) * (x + 1) - sum(tr2, x);
35 }
36
37 int main()
38 {
39 scanf("%d%d", &n, &m);
40 for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
41
42 for (int i = 1; i <= n; i ++ )
43 {
44 int x = a[i] - a[i - 1];
45 add(tr1, i, x); add(tr2, i, (LL)x * i);
46 }
47
48 while (m -- )
49 {
50 char s[2];
51 scanf("%s", s);
52 if (*s == 'C')
53 {
54 int l, r, k;
55 scanf("%d%d%d", &l, &r, &k);
56 add(tr1, l, k), add(tr1, r + 1, -k);
57 add(tr2, l, k * l), add(tr2, r + 1, (r + 1) * (-k));
58 }
59 else
60 {
61 int l, r;
62 scanf("%d%d", &l, &r);
63 printf("%lld\n", per_sum(r) - per_sum(l - 1));
64 }
65 }
66
67 return 0;
68 }
第一个操作需要我们将区间中的每个数全部加上x那么我们树状数组存储的则是差分数组,而第二个操作需要我们求出前缀和,那么我们则要对题目条件进行处理。
黑色部分使我们需要查询操作需要求出来的部分,红色部分是后来补上。
则这样我们的黑色部分则为整个矩阵的和减去红色部分的和,即(a[1] + a[2] + a[3] + ...... + a[n]) * (n + 1) - (a[1] + 2a[2] + 3a[3] + ...... + na[n])。
而这个a数组使我们存储在树状数组中的值,则我们的公式变为了sum(n) * (n + 1) - sumi(n)。
所以我们需要存储两个树状数组,一个存储ai,一个存储i * ai。