对应 POJ 题目:点击打开链接
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 22905 | Accepted: 8492 |
Description
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 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
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,表示有 X 组数据;然后输入两个数 N,T;N 表示初始值为全 0 的 N*N 矩阵,T 表示有 T 个操作;接下来 T 行操作:(C x1 y1 x2 y2) 表示把以 (x1, y1) 坐标为左上角,(x2, y2) 坐标为右下角的矩阵的属性翻转(如果是 1 的变为 0,是 0 的变为 1);(Q x y) 表示询问 (x y) 坐标的点的属性(是 1 或 0)。
思路:
二维树状数组(基础:点击打开链接 点进去下面有翻译 或 点击打开链接)。
先来看一维的情况:
n张卡片摆成一排,分别为第1张到第n张,开始时它们都是下面朝下的。你有两种操作:
T(i,j):将第i张到第j张卡片进行翻转,包含i和j这两张。(正面变反面,反面变正面)
Q(i):如果第i张卡片正面朝下,返回0;否则返回1.
解决方案:
设数组f初始全为0,当做一次T(i, j)操作后, 将f[i]加1,f[j+1]减1。这样一来,当我们做一次Q(i)时,只需要求f数组的前i项和sum[i] ,然后对2取模即可。当我们做完一次T(i, j)后,f[i]=1,f[j+1]=-1。 这样一来,当k<i时,sum[k]%2=0,表明正面朝下;当i<=k<=j时,sum[k]%2=1,表明正面朝 上(因为这区间的卡片都被翻转了!);当k>j时,sum[k]%2=0,表示卡片正面朝下。 Q(i)返回的正是我们要的判断。
二维的也可以用类似的方法,(注意坐标轴的轴心是在左上角,不是左下角)。把以 (x1, y1) 坐标为左上角,(x2, y2) 坐标为右下角的矩阵的属性取反,就相当于在点 (x1, y1) 加 1,点 (x2 +1, y1) 减 1,点 (x1, y2 +1) 减 1,点 (x2 + 1, y2 + 1) 加 1;而求矩阵中某点的属性就相当于对以 (1, 1) 坐标为左上角,(x, y) 坐标为右下角的矩阵的元素求和然后对 2 取模;在理解了二维树状数组后,这点不难理解。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 1005
#define max_x 1000
#define max_y 1000
int c[N][N];
int lowbit(int x)
{
return (x & (-x));
}
void update(int x, int y, int val)
{
while(x <= max_x){
int yt = y;
while(yt <= max_y){
c[x][yt] += val;
yt += lowbit(yt);
}
x += lowbit(x);
}
}
int query(int x, int y)
{
int s = 0;
while(x > 0){
int yt = y;
while(yt > 0){
s += c[x][yt];
yt -= lowbit(yt);
}
x -= lowbit(x);
}
return s;
}
int main()
{
#if 0
freopen("in.txt","r",stdin);
#endif
int T;
scanf("%d", &T);
while(T--){
int n, m;
char od[3];
memset(c, 0, sizeof(c));
scanf("%d%d", &n, &m);
while(m--){
scanf("%s", od);
if(od[0] == 'C'){
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
update(x1, y1, 1);
update(x2 + 1, y1, -1);
update(x1, y2 + 1, -1);
update(x2 + 1, y2 + 1, 1);
}
else if(od[0] == 'Q'){
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", query(x, y) % 2);
}
}
if(T) printf("\n");
}
return 0;
}