# “高级”数据结构——树状数组！

※本文一切代码未经编译，不保证正确性，如发现问题，欢迎指正！

## 1. 单点修改 + 区间查询

void add(int p, int x){ //给位置p增加x
while(p <= n) sum[p] += x, p += p & -p;
}
int res = 0;
while(p) res += sum[p], p -= p & -p;
return res;
}
int range_ask(int l, int r){ //区间求和
}


## 2. 区间修改 + 单点查询

### 修改

void add(int p, int x){ //这个函数用来在树状数组中直接修改
while(p <= n) sum[p] += x, p += p & -p;
}
void range_add(int l, int r, int x){ //给区间[l, r]加上x
}
int res = 0;
while(p) res += sum[p], p -= p & -p;
return res;
}


## 3. 区间修改 + 区间查询

$\sum_{i = 1}^{p} a[i] = \sum_{i = 1}^{p} \sum_{j = 1}^{i} d[j]$

$\sum_{i = 1}^{p} \sum_{j = 1}^{i} d[j] = \sum_{i = 1}^{p} d[i] * (p - i + 1) = (p + 1) * \sum_{i = 1}^{p}d[i] - \sum_{i = 1}^{p}d[i]*i$

### 修改

void add(ll p, ll x){
for(int i = p; i <= n; i += i & -i)
sum1[i] += x, sum2[i] += x * p;
}
void range_add(ll l, ll r, ll x){
}
ll res = 0;
for(int i = p; i; i -= i & -i)
res += (p + 1) * sum1[i] - sum2[i];
return res;
}
}


## 4. 二维树状数组

### 单点修改 + 区间查询

void add(int x, int y, int z){ //将点(x, y)加上z
int memo_y = y;
while(x <= n){
y = memo_y;
while(y <= n)
tree[x][y] += z, y += y & -y;
x += x & -x;
}
}
void ask(int x, int y){//求左上角为(1,1)右下角为(x,y) 的矩阵和
int res = 0, memo_y = y;
while(x){
y = memo_y;
while(y)
res += tree[x][y], y -= y & -y;
x -= x & -x;
}
}


### 区间修改 + 单点查询

$sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j]$

 1  4  8
6  7  2
3  9  5


 1  3  4
5 -2 -9
-3  5  1


0  0  0  0  0
0 +x  0  0 -x
0  0  0  0  0
0  0  0  0  0
0 -x  0  0 +x


0  0  0  0  0
0  x  x  x  0
0  x  x  x  0
0  x  x  x  0
0  0  0  0  0


void add(int x, int y, int z){
int memo_y = y;
while(x <= n){
y = memo_y;
while(y <= n)
tree[x][y] += z, y += y & -y;
x += x & -x;
}
}
void range_add(int xa, int ya, int xb, int yb, int z){
add(xb + 1, yb + 1, z);
}
int res = 0, memo_y = y;
while(x){
y = memo_y;
while(y)
res += tree[x][y], y -= y & -y;
x -= x & -x;
}
}


### 区间修改 + 区间查询

$\sum_{i=1}^{x}\sum_{j=1}^{y}\sum_{k=1}^{i}\sum_{h=1}^{j}d[h][k] (d[h][k]为点(h, k)对应的“二维差分”(同上题)) 这个式子炒鸡复杂( O(n^4) 复杂度！)，但利用树状数组，我们可以把它优化到 O(\log^2n)！ 首先，类比一维数组，统计一下每个d[h][k]出现过多少次。d[1][1]出现了x*y次，d[1][2]出现了x*(y - 1)次……d[h][k] 出现了 (x - h + 1)*(y - k + 1) 次。 那么这个式子就可以写成： \sum_{i=1}^{x}\sum_{j=1}^{y}d[i][j] * (x + 1 - i) * (y + 1 - j)$

$(x + 1) * (y + 1) * \sum_{i=1}^{x}\sum_{j=1}^{y}d[i][j]$

$- (y + 1) * \sum_{i=1}^{x}\sum_{j=1}^{y}d[i][j] * i$

$- (x + 1) * \sum_{i=1}^{x}\sum_{j=1}^{y}d[i][j] * j$

$+ \sum_{i=1}^{x}\sum_{j=1}^{y}d[i][j] * i * j$

$$d[i][j], d[i][j] * i, d[i][j] * j, d[i][j] * i * j$$

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
char c; bool op = 0;
while((c = getchar()) < '0' || c > '9')
if(c == '-') op = 1;
ll res = c - '0';
while((c = getchar()) >= '0' && c <= '9')
res = res * 10 + c - '0';
return op ? -res : res;
}
const int N = 205;
ll n, m, Q;
ll t1[N][N], t2[N][N], t3[N][N], t4[N][N];
void add(ll x, ll y, ll z){
for(int X = x; X <= n; X += X & -X)
for(int Y = y; Y <= m; Y += Y & -Y){
t1[X][Y] += z;
t2[X][Y] += z * x;
t3[X][Y] += z * y;
t4[X][Y] += z * x * y;
}
}
void range_add(ll xa, ll ya, ll xb, ll yb, ll z){ //(xa, ya) 到 (xb, yb) 的矩形
add(xb + 1, yb + 1, z);
}
ll res = 0;
for(int i = x; i; i -= i & -i)
for(int j = y; j; j -= j & -j)
res += (x + 1) * (y + 1) * t1[i][j]
- (y + 1) * t2[i][j]
- (x + 1) * t3[i][j]
+ t4[i][j];
return res;
}
ll range_ask(ll xa, ll ya, ll xb, ll yb){
}
int main(){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
}
}
while(Q--){