经典算法 | 二维树状数组

给定一个二维数组,给定两种操作,第一种,输入s x1 y1 x2 y2,表示查询二维数组中(x1,y1)到(x2,y2)这一段矩形中所有数的和,第二组操作为a x1 y1 value,表示将数组中num[x1][y1]的数加value,如何在最快的时间内得到结果

这里可以使用二维树状数组,

首先是lowBit(n),这个函数的功能是返回n最低位的1所代表的数的大小,比如5,其二进制为101,那么其最低位的1为1,对于二进制101000而言,其最低位的1为1000,lowBit有两种实现方式,一种为n – (n & (n – 1)),第二种为n & (-n),第二种利用的补码的性质,这两种方式的结果其实是一样的。

这里使用一个辅助数组tree_list,tree_list[n]表示tree_list[n] + tree_list[n-1]+。。。tree_list[n – lowBit(n)],这是一维的情况,二维的tree_list是二维的,并且原理是一样的

当修改num[x]的时候,所有n > x,n – lowBit(n) < x的n,其tree_list[n]都需要修改,使用for(int i=x;i<=size();i+=lowBit(i))能够找到所有的小于size()的满足要求的n,这是一维的处理,二维的处理方式是相同的。

这里需要注意x代表行数,y代表列数,当行遍历或者是列遍历的时候需要注意for循环的条件,还需要注意当查询数字段的时候需要注意减一的问题。

#include<iostream>
using namespace std; 

int tree_list[1001][1001] = { 0 };

int lowBit(int x)
{
	return x & (-x);
}
int search(int x, int y)
{
	int result = 0;
	for (int i = x; i > 0; i -= lowBit(i))
		for (int j = y; j > 0; j -= lowBit(j))
			result += tree_list[i][j];
	return result;
}

void add(int x, int y, int value, int w,int h)
{
	for (int i = x; i <= h; i += lowBit(i))
		for (int j = y; j <= w; j += lowBit(j))
			tree_list[i][j] += value;
}

int main()
{
	int num[][6] = {
	{0, 0, 0, 0, 0, 0},
	{0, 1, 2, 3, 4, 5},
	{0, 6, 7, 8, 1, 1},
	{0, 6, 7, 8, 1, 1 },
	{0, 1, 1, 1, 1, 1 }
	};
	int h = 4;
	int w = 5;//行和列的数据编号都是从1开始的
	for(int i=1;i<=h;i++)
		for (int j = 1; j <= w; j++)
		{
			add(i, j, num[i][j], w, h);
		}
	char j_type = 'a';
	int x, y, v;
	int x2, y2;
	while (cin >> j_type)
	{
		if (j_type == 'a')
		{
			cin >> x >> y >> v;
			add(x, y, v, w, h);
		}
		else
		{
			cin >> x >> y >> x2 >> y2;
			int A1, A2, A3, A4;
			A1 = search(x-1, y-1);
			A2 = search(x2, y2);
			A3 = search(x-1, y2);
			A4 = search(x2, y-1);
			cout << A2 - A3 - A4 + A1 << endl;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/u012737193/article/details/82829654