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。