二维树状数组 —— POJ 2155 Matrix

对应 POJ 题目:点击打开链接

Matrix
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 22905   Accepted: 8492

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,表示有 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)返回的正是我们要的判断。


二维树状数组 —— POJ 2155 Matrix_第1张图片

        二维的也可以用类似的方法,(注意坐标轴的轴心是在左上角,不是左下角)。把以 (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 取模;在理解了二维树状数组后,这点不难理解。


二维树状数组 —— POJ 2155 Matrix_第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;
}



你可能感兴趣的:(二维树状数组 —— POJ 2155 Matrix)