您的位置:首页 > 其它

POJ2155 二维树状数组求区域和

2016-03-19 22:05 288 查看
题意 : 有一个N*N 的网格,X组测试样例,一开始网格之中的数全为 0 。输入一个操作数 T,有两种操作,C代表修改,意思是将 (X1,Y1)和(X2,Y2)围成一个矩形区域中的数全部取“非”(即原本是0的变成1,原本是1的改为0)。Q代表查询,意思是查询(X,Y)网格中的数字。

对于这道题一开始想到的是二维线段树的区间更新,但写起来麻烦,后来想到了一个巧妙的思想:对于网格中的数字,我们只需要知道它的修改次数就可以了,但是如果不用区间更新的话就会超时,原因是N * N * T的复杂度,其实如果只去标记被围住的区间的几个必要点就可以了。举个一维的例子来看,如果要修改(X,Y)区间的数字,那么只需要将 X 点和 Y+1 点处加1 就可以了,这样再询问某个点数字的时候,1到 该点 的和就是我们对这个数字修改过的次数。 二维的情况参照一维并扩展成四个点就好。而树状数组正是实现数组 1-n 处求和的好方式。

代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=1e3+5;
int bit[maxn][maxn];
int n,q;

int sum(int x,int y){
int s=0;
for(int i=x;i>0;i-=(i&-i)){
for(int j=y;j>0;j-=(j&-j)){
s+=bit[i][j];
}
}
return s;
}

void add(int x,int y,int v){
for(int i=x;i<=n;i+=(i&-i)){
for(int j=y;j<=n;j+=(j&-j)){
bit[i][j]+=v;
}
}
}

int main()
{
//ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--){
memset(bit,0,sizeof(bit));
cin>>n>>q;
while(q--){
char temp[2];
scanf("%s",temp);
if(temp[0]=='Q'){
int x,y;
char k;
scanf("%d %d",&x,&y);
int s=sum(x,y);
if(s & 1) cout<<"1"<<endl;
else      cout<<"0"<<endl;
}
if(temp[0]=='C'){
int x1,y1,x2,y2;
char k;
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
add(x1,y1,1);
add(x1,y2+1,1);
add(x2+1,y1,1);
add(x2+1,y2+1,1);
}
}
cout<<endl;
}
//system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: