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;
}
时间: 2024-10-17 11:52:27

poj_1190 树状数组的相关文章

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

(POJ 3067) Japan (慢慢熟悉的树状数组)

Japan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29295   Accepted: 7902 Description Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Japan is tall island with N cities on the East coas

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

CF 313 DIV2 B 树状数组

http://codeforces.com/contest/313/problem/B 题目大意 给一个区间,问你这个区间里面有几个连续相同的字符. 思路: 表示个人用树状数组来写的...了解了树状数组的本质就行了. 当然用sum[r]-sum[l]也是可以的

Hdu5032 极角排序+树状数组

题目链接 思路:参考了题解.对询问进行极角排序,然后用树状数组维护一下前缀和即可. /* ID: onlyazh1 LANG: C++ TASK: test */ #include<bits/stdc++.h> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 typedef long long ll; const int maxn=1010; const int maxm=10

Curious Robin Hood(树状数组+线段树)

1112 - Curious Robin Hood    PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 64 MB Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money together he does another tri

【初识——树状数组】 区间求最值

说树状数组其实是一个索引表,但是是一个特殊的,树状的索引表,它利用了二进制的一些特性. 就区间求和的要求来说: 首先我们用a[]数组来存储原始数据.然后在a[]之上构造c[]数组来作为树状数组. 如图 这个图表示,当i为奇数时,c[i]中保存的都是a[i]本身.然后,c[2]中保存了a[1], a[2],共2个,c[4]中保存的是a[1], a[2], a[3], a[4],c[6]又是保存两个,c[5]和c[6].c[8]保存8个,c[1], c[2], c[3], c[4], c[5], c

树状数组求区间最大值

------  一直用 线段树 求区间最大值,想换种思路,用树状数组试试,肯定是可以的. 首先要对 树状数组的每个 i 所管理的区间有一定的理解.详见上篇博客: 树状数组(BIT)