您的位置:首页 > 其它

poj 2155 Matrix(二维树状数组)

2017-04-06 22:11 369 查看
Matrix

Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 26929 Accepted: 9867
Description

Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1 <= i, j <= N). 

We can change the matrix in the following way. Given a rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2), we change all the elements in the rectangle by using "not" operation (if it is a '0' then change it into '1' otherwise change
it into '0'). To maintain the information of the matrix, you are asked to write a program to receive and execute two kinds of instructions. 

1. C x1 y1 x2 y2 (1 <= x1 <= x2 <= n, 1 <= y1 <= y2 <= n) changes the matrix by using the rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2). 

2. Q x y (1 <= x, y <= n) querys A[x, y]. 

Input

The first line of the input is an integer X (X <= 10) representing the number of test cases. The following X blocks each represents a test case. 

The first line of each block contains two numbers N and T (2 <= N <= 1000, 1 <= T <= 50000) representing the size of the matrix and the number of the instructions. The following T lines each represents an instruction having the format "Q x y" or "C x1 y1 x2
y2", which has been described above. 

Output

For each querying output one line, which has an integer representing A[x, y]. 

There is a blank line between every two continuous test cases. 

Sample Input
1
2 10
C 2 1 2 2
Q 2 2
C 2 1 2 1
Q 1 1
C 1 1 2 1
C 1 2 1 2
C 1 1 2 2
Q 1 1
C 1 1 2 1
Q 2 1

Sample Output
1
0
0
1


这个题暴力肯定是不能过的,这个地方利用了二维树状数组来维护。

不会二维树状数组的请仔细查看博客一维与二维树状数组。

老实说一开始看题解,是怎么也看不懂,实际上树状数组的功能确实没问题,然而在理解上有一些问题。

首先要明确树状数组的板子代表的意思。

假设参数都是x,y,val。

1.updata函数,更新的是a[x][y]的值。

2.ask函数,查询出来的是以(1,1)为左上角以(x,y)为右下角的子矩阵的和!!!!

对于这个题怎么来做呢,这个地方其实是利用了用标记来消除影响的一个效果。

譬如说对于一个1维数组,你要更新区间(l,r)的值,那么你可以让a[l]+val,让a[r+1]-val,这样你从左端加到右端(假设为x)的时候(前缀和)算出来的a[x]的值是正确的。

就是说每一个a[i]的值都是这样得到的a[i]+=a[i-1]。

可以在纸上画一画,便知道了。

然后这个题其实就是把这个方法延伸到了二维上了。

我们更新的是(x1,y1)到(x2,y2)这个子矩阵的值。

那么我们把

1.(x1,y1)+val.

2.(x1,y2+1)-val;

3.(x2+1,y1)-val;

4.(x2+1,y2+1)+val;

这样我们在计算a[x][y]的值的时候,便是从(1,1)端点加到(x,y)端点的值的和了。

表示看了好多题解也没怎么弄懂,最后自己画图终于搞懂了,问了几个也是迷迷糊糊,实际上树状数组的功能很明确就是上面说的。

这个工具到底干了什么,我想很多写出题解的人也不知道吧,这样是无法举一反三的。也无法很好的使用树状数组这个工具。

#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN=1e5+7;
int n,m,k;
char s[2];
int tu[1005][1005];
int lowbit(int i)
{
return i&(-i);
}
void add(int x,int y,int d)
{
for(int i=x; i<=n; i+=lowbit(i))
for(int j=y; j<=n; j+=lowbit(j))tu[i][j]+=d;
}
int ask(int x,int y)
{
int sum=0;
for(int i=x; i>0; i-=lowbit(i))
for(int j=y; j>0; j-=lowbit(j))sum+=tu[i][j];
return sum;
}
int main()
{
int t;
scanf("%d",&t);
int x1,y1,x2,y2;
while(t--)
{
memset(tu,0,sizeof(tu));
scanf("%d%d",&n,&m);
while(m--)
{
scanf("%s",s);
if(s[0]=='C')
{
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);
}
else
{
scanf("%d%d",&x2,&y2);
int ans=ask(x2,y2);
printf("%d\n",ans%2);
}
}
if(t)puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息