1. 程式人生 > 實用技巧 >Acwing 243. 一個簡單的整數問題2 —— 差分樹狀陣列(複雜引用版本)

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。