Acwing 243. 一个简单的整数问题2 —— 差分树状数组(复杂引用版本)

题目链接: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。

posted @ 2020-12-29 18:28  筱翼深凉  阅读(134)  评论(0编辑  收藏  举报