poj_1190 树状数组
题目大意
给定一个S*S的矩形,该矩形由S*S个1x1的单元格构成,每个单元格内可以放一个整数,每次有如下可能操作:
(1)改变某个单位单元格中的数的大小
(2)查询由若干个连续单元格构成的X*Y的大小的矩形内所有数的总和
题目分析
典型的区间操作,而且是单点更新,区间查询。因此使用树状数组,不过应该使用二维树状数组。二维树状数组和一维其实没什么区别。。。。
另:用线段树也做了一份,但是超时,果然树状数组在效率上还是略胜线段树的。下面给出树状数组的AC代码和线段树的TLE代码。
实现(c++)
1.树状数组
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #define MAX_SQUARE_SIZE 1025 #define MAX(a, b) a>b? a:b #define MIN(a, b) a <b? a:b int gLowBit[MAX_SQUARE_SIZE]; int gC[MAX_SQUARE_SIZE][MAX_SQUARE_SIZE]; void InitLowBit(int n){ for (int i = 1; i <= n; i++){ gLowBit[i] = i&(-i); } } void InitSequence(int n){ memset(gC, 0, sizeof(gC)); } void Update(int x, int y, int n, int add){ int tmp_y = y; while (x <= n){ y = tmp_y; while (y <= n){ gC[x][y] += add; y += gLowBit[y]; } x += gLowBit[x]; } } int Query1(int x, int y){ int tmp_y = y, result = 0; while (x > 0){ y = tmp_y; while (y > 0){ result += gC[x][y]; y -= gLowBit[y]; } x -= gLowBit[x]; } return result; } int Query(int left, int right, int bottom, int top){ int r_t = Query1(right, top); int l_t = Query1(left - 1, top); int r_b = Query1(right, bottom - 1); int l_b = Query1(left - 1, bottom - 1); //注意在查询的时候,需要计算的矩形的边界弄清楚 [i , ... j] = sum(j) = sum(i - 1) return (r_t + l_b - l_t - r_b); } int main(){ int ins; int S, X, Y, A, L, B, R, T; scanf("%d %d", &ins, &S); InitLowBit(S); InitSequence(S); while (scanf("%d", &ins)){ if (ins == 3){ break; } if (ins == 1){ scanf("%d %d %d", &X, &Y, &A); Update(X+1, Y+1, S, A); } else if (ins == 2){ scanf("%d %d %d %d", &L, &B, &R, &T); int result = Query(L+1, R+1, B+1, T+1); printf("%d\n", result); } } return 0; }
2.线段树
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #define MAX_SQUARE_SIZE 1025 #define MAX_NODE_NUM MAX_SQUARE_SIZE*4 #define MAX(a, b) a>b? a:b #define MIN(a, b) a <b? a:b struct Node{ short left; short right; short top; short bottom; int sum_phones; short h_mid(){ return (left + right) >> 1; } short v_mid(){ return (top + bottom) >> 1; } }; Node gNodes[MAX_NODE_NUM][MAX_NODE_NUM]; void BuildTree(int h_index, int v_index, short left, short right, short bottom, short top){ gNodes[h_index][v_index].left = left; gNodes[h_index][v_index].right = right; gNodes[h_index][v_index].top = top; gNodes[h_index][v_index].bottom = bottom; gNodes[h_index][v_index].sum_phones = 0; if (left == right || top == bottom){ return; } int left_child = 2 * h_index + 1, right_child = 2 * h_index + 2; int up_child = 2 * v_index + 1, down_child = 2 * v_index + 2; short h_mid = (left + right) >> 1, v_mid = (top + bottom) >> 1; BuildTree(left_child, down_child, left, h_mid, bottom, v_mid); BuildTree(right_child, down_child, h_mid + 1, right, bottom, v_mid); BuildTree(left_child, up_child, left, h_mid, v_mid + 1, top); BuildTree(right_child, up_child, h_mid + 1, right, v_mid + 1, top); } void Update(int h_index, int v_index, short left, short right, short bottom, short top, int add){ if (gNodes[h_index][v_index].left == gNodes[h_index][v_index].right){ //arrive to the point gNodes[h_index][v_index].sum_phones += add; return; } if (left > gNodes[h_index][v_index].right || right < gNodes[h_index][v_index].left || top < gNodes[h_index][v_index].bottom || bottom > gNodes[h_index][v_index].top){ return; } if (left > right || bottom > top){ return; } int left_child = 2 * h_index + 1, right_child = 2 * h_index + 2; int up_child = 2 * v_index + 1, down_child = 2 * v_index + 2; short h_mid = gNodes[h_index][v_index].h_mid(), v_mid = gNodes[h_index][v_index].v_mid(); gNodes[h_index][v_index].sum_phones += add; Update(left_child, down_child, left, MIN(right, h_mid), bottom, MIN(top, v_mid), add); Update(left_child, up_child, left, MIN(right, h_mid), MAX(v_mid + 1, bottom), top, add); Update(right_child, down_child, MAX(left, h_mid + 1), right, bottom, MIN(top, v_mid), add); Update(right_child, down_child, MAX(left, h_mid + 1), right, MAX(v_mid + 1, bottom), top, add); } int Query(int h_index, int v_index, short left, short right, short bottom, short top){ if (left == right || top == bottom){ //arrive to the point return gNodes[h_index][v_index].sum_phones; } if (left > gNodes[h_index][v_index].right || right < gNodes[h_index][v_index].left || top < gNodes[h_index][v_index].bottom || bottom > gNodes[h_index][v_index].top){ return 0; } if (left > right || bottom > top){ return 0; } int left_child = 2 * h_index + 1, right_child = 2 * h_index + 2; int up_child = 2 * v_index + 1, down_child = 2 * v_index + 2; short h_mid = gNodes[h_index][v_index].h_mid(), v_mid = gNodes[h_index][v_index].v_mid(); int result = 0; result += Query(left_child, down_child, left, MIN(right, h_mid), bottom, MIN(top, v_mid)); result += Query(left_child, up_child, left, MIN(right, h_mid), MAX(v_mid + 1, bottom), top); result += Query(right_child, down_child, MAX(left, h_mid + 1), right, bottom, MIN(top, v_mid)); result += Query(right_child, down_child, MAX(left, h_mid + 1), right, MAX(v_mid + 1, bottom), top); return result; } int main(){ int ins; int S, X, Y, A, L, B, R, T; scanf("%d %d", &ins, &S); BuildTree(0, 0, 0, S - 1, 0, S - 1); while (scanf("%d", &ins)){ if (ins == 3){ break; } if (ins == 1){ scanf("%d %d %d", &X, &Y, &A); Update(0, 0, X, X, Y, Y, A); } else if (ins == 2){ scanf("%d %d %d %d", &L, &B, &R, &T); int result = Query(0, 0, L, R, B, T); printf("%d\n", result); } } return 0; }