给定一个二维数组,给定两种操作,第一种,输入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
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;
}