题目链接:http://poj.org/problem?id=1195
题目意思:有一部 mobie phone 基站,它的面积被分成一个个小正方形(1 * 1 的大小),所有的小正方形的面积构成了一个 S * S 大小的矩阵(下标都是从 0 ~ S-1 变化的)。
有四种指令:
第 一 行的指令默认输入是 0, 空格之后是矩阵的大小: S
最后一行的指令是 3, 代表 整个输入结束
注意:这两行的指令只会出现一次!
夹在它们中间的指令有可能是指令1,假设为X Y A,代表向第 X 行 第 Y 列的那个小正方形加上A (可正可负),不需要输出结果。 又或者是指令2,假设为 L B R T,代表要计算出 行 L ~ R,列 B ~ T 所围住的矩形的和,这个指令要求输出这个和。
看了很久,终于看明白题目了,表示英文太差,经常看不懂POJ 的英文题 = =。
二维树状数组,有了前一天二维树状数组探索版的积累,套了下模板。不过询问那里,也就是指令 2 的输出有点问题,今天终于改好了,happy ^_^ ....
首先要知道二维树状数组这个模板的 Sum 究竟算出来的是什么:假如调用的是Sum(i, j)啦,那么它求出的是从最左上角的坐标到坐标 (i, j) 所围的面积的和!!! 那么如果要求特定的某个子矩阵的面积(例如 (2, 3) ~ (3,4)),就需要减去相应不需要的部分啦。
数字4 是我们要求的部分,如果单纯调用Sum(3, 4) 的话,得出的是编号 1 的和,那么我们需要减去2和3的和,才能得出4的和,而要得出2的和,也需要减去[A11 + A12]这个矩阵的和啦,也就是Sum(3, 2) - Sum(1, 2),对应代码中的 Sum(R+1, B)-Sum(L, B)。而编号 3 的和对应代码: Sum(L, T+1)。
(之前错误地写成Sum(3, 4)- Sum(2, 3) 了, = =,粗心呀~~~,读者请忽略)
还有一个值得注意的地方是,树状数组下标是从1开始的,而题目坐标是从0开始的,所以不妨相应地向右下角移动一位,就是说,假设输入的是0 0,那么就看成是1 1 (这个是受hdu 1541 的 Stars 启发啦)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn = 1024 + 10; 7 int A[maxn][maxn]; 8 int C[maxn][maxn]; 9 int size; 10 11 int lowbit(int x) 12 { 13 return x & (-x); 14 } 15 16 int Sum(int i, int j) 17 { 18 int result = 0; 19 for (int x = i; x > 0; x -= lowbit(x)) 20 { 21 for (int y = j; y > 0; y -= lowbit(y)) 22 result += C[x][y]; 23 } 24 return result; 25 } 26 27 void Modify(int i, int j, int delta) 28 { 29 A[i][j] += delta; 30 31 for (int x = i; x < size+1; x += lowbit(x)) 32 { 33 for (int y = j; y < size+1; y += lowbit(y)) 34 C[x][y] += delta; 35 } 36 } 37 38 int main() 39 { 40 int x, y, ask, num, L, B, R, T; 41 memset(A, 0, sizeof(A)); 42 memset(C, 0, sizeof(C)); 43 while (scanf("%d", &ask) != EOF && ask != 3) 44 { 45 if (ask == 0) 46 scanf("%d", &size); 47 else if (ask == 1) 48 { 49 scanf("%d%d%d", &x, &y, &num); 50 Modify(x+1, y+1, num); 51 } 52 else if (ask == 2) 53 { 54 scanf("%d%d%d%d", &L, &B, &R, &T); 55 printf("%d ", Sum(R+1, T+1)-(Sum(R+1, B)-Sum(L, B))- Sum(L, T+1)); // 对应图中的1-2-3 56 } 57 } 58 return 0; 59 }