BZOJ 3132 上帝造题的七分钟【二维树状数组】

题意:

给定$n \times m$的矩阵,$k$个操作,每个操作给定矩阵左上角和右下角顶点,有两种操作,一是将该矩阵全部元素加上$x$,二是询问该矩阵全部元素的和。
数据范围:$0 \le n,m \le 2048, k \le 200000, 0 \le x \le 500$,保证计算过程中所有数不超过带符号整型。

分析:

区间求和问题我们可以转化为前缀和问题,即对于$[a,b]和[c,d]$之间的矩阵答案为$sum(c,d)-sum(c, b-1)-sum(a-1,d)+sum(a,b)$,这样就可以变为单点查询。
对于区间修改问题,我们利用差分的思想,将区间修改转化为单点修改。
令每个位置的元素为$newa_{i,j} = a_{i,j}-a_{i-1,j}-a_{i,j-1}+a_{i-1,j-1}$,那么$a_{x,y}=\sum_{i=1}^x \sum_{j=1}^y newa_{i,j}$
$sum(a,b)=\sum_{x=1}^a\sum_{y=1}^b a_{x,y}=\sum_{x=1}^a\sum_{y=1}^b \sum_{i=1}^x \sum_{j=1}^y newa_{i,j}$
考虑$[1,1]$内每个元素对于$sum(a,b)$的贡献,
$sum(a,b)=\sum_{i=1}^a\sum_{j=1}^b (a + 1 - i) \times (b + 1 - j) \times newa_{x,y} $
$= (a+1) \times (b+1)\sum_{i=1}^a\sum_{j=1}^b newa_{i,j}- (a+1) \sum_{i=1}^a\sum_{j=1}^b newa_{i,j}\times j-(b+1)\sum_{i=1}^a\sum_{j=1}^b newa_{i,j}\times i$
$+ \sum_{i=1}^a\sum_{j=1}^b i \times j \times newa_{i,j}$
这样对于每个点分别记录这四个值,单点更新单点查询套个二维树状数组即可。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*************************************************************************
> File Name: 3132.cpp
> Author: jiangyuzhu
> Mail: 834138558@qq.com
> Created Time: 2016/9/27 10:50:42
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 2500 + 5;
int bit[maxn][maxn][5];
void add(int x, int y, int val, int id)
{
for (int i = x; i < maxn; i += i & (-i)) {
for (int j = y; j < maxn; j += j & (-j)){
bit[i][j][id] += val;
}
}
}
int sum(int x, int y, int id)
{
int res = 0;
for(int i = x; i; i -= i & (-i)){
for(int j = y; j; j -= j & (-j)){
res += bit[i][j][id];
}
}
return res;
}
void Add(int a, int b, int dt)
{
add(a, b, dt, 1); add(a, b, dt * b, 2); add(a, b, dt * a, 3); add(a, b, dt * a * b, 4);
}
int Query(int c, int d)
{
int ans = (c + 1) * (d + 1) * sum(c, d, 1) - (d + 1) * sum(c, d, 3) - (c + 1) * sum(c, d, 2) + sum(c, d, 4);
return ans;
}
char s[10];
int main (void)
{
int n, m;scanf("%s%d%d", s, &n, &m);
int a, b, c, d, dt;
memset(bit, 0 ,sizeof(bit));
while(~scanf("%s", s)){
if(s[0] == 'L'){
scanf("%d%d%d%d%d", &a, &b, &c, &d, &dt);
Add(a, b, dt);
Add(a, d + 1, -dt);
Add(c + 1, b, -dt);
Add(c + 1, d + 1, dt);
}else{
scanf("%d%d%d%d", &a, &b, &c, &d);
if(a > c || b > d) swap(a, b), swap(c, d);
printf("%d\n", Query(c, d) - Query(a - 1, d) - Query(c, b - 1) + Query(a - 1, b - 1));
}
}
return 0;
}
文章目录
  1. 1. 题意:
  2. 2. 分析:
  3. 3. 代码: