POJ 1195 Mobile phones(二維樹狀數組)
阿新 • • 發佈:2017-08-15
給定 ostream 題意 == turn += ret 一個 合成
題目鏈接:POJ 1195
題意:
給出一個S*S的矩陣(行、列號從1開始),每個元素初始值為0,有兩種操作:一種是第X行第Y列元素值加A;另一種是查詢給定範圍矩陣的所有元素之和(L<=X<=R,B<=Y<=T)。
分析:
查詢給定範圍矩陣的所有元素之和是二維區間和,可以轉換為二維前綴和求值。類比一維前綴和求法,二維區間和S(L, B, R, T) = S(1, 1, R, T) - S(1 ,1, L-1, T) - S(1, 1, R, B-1) + S(1, 1, L-1, B-1)。單點更新一個元素的值,修改二維前綴和,類比一維樹狀數組的更新操作,二維樹狀數組的更新操作(參考代碼)。
總結:
二維樹狀數組可以理解為:先固定X=i,把Y=1~S看作一維樹狀數組就比較容易理解,再X=1~S看作一維樹狀數組,這樣組合成二維樹狀數組。如果還想不明白,可以想想二元積分是怎麽做的。
代碼實現:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cmath> using namespace std; const int N = 1024 + 5; int C[N][N], cmd, s, x, y, a, l, b, r, t; int lowbit(int x) { return x & (-x); } void add(int x, int y, int a) { for (int i = x; i <= s; i += lowbit(i)) for (int j = y; j <= s; j += lowbit(j)) C[i][j] += a; } int sum(int x, int y) { int ret = 0; for (int i = x; i; i -= lowbit(i)) for (int j = y; j; j -= lowbit(j)) ret += C[i][j]; return ret; } int main() { while (~scanf("%d", &cmd)) { if (cmd == 3) break; if (cmd == 0) { scanf("%d", &s); for (int i = 1; i <= s; i++) for (int j = 1; j <= s; j++) C[i][j] = 0; continue; } if (cmd == 1) { scanf("%d%d%d", &x, &y, &a); x++, y++; add(x, y, a); continue; } if (cmd == 2) { scanf("%d%d%d%d", &l, &b, &r, &t); l++, b++, r++, t++; int ans = sum(r, t) - sum(l-1, t) - sum(r, b-1) + sum(l-1, b-1); printf("%d\n", ans); } } return 0; }
POJ 1195 Mobile phones(二維樹狀數組)