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;
}

 

posted @ 2015-09-06 23:49  农民伯伯-Coding  阅读(384)  评论(0编辑  收藏  举报