【原】 POJ 2155 Matrix 2D树状数组 解题报告
http://poj.org/problem?id=2155
题目要求修改一个区域,然后求一个元素的值。貌似和树状数组的功能完全相反。但这题,应该
说这个思路的精妙之处就体现在这里。我认为关键是要理解“树状”的概念。画一个一维的树状数
组图形,就会发现所有的元素都会链接到2,4,8,16,32……这条“主干”上来。那么,修改了“主干”,
其实就相当于修改了整个“树”。
对于每个元素a,“主干”可以分为两个部分,
Up(a) = { a1 = a, a2 = a1+ lowbit(a1), a3 = a2 + lowbit(a2), ... }
Down(a) = { a1 =a, a2 = a1 -lowbit(a1), a3 = a2 - lowbit(a2), ... }。
当然这里不是完全的对应主干上的每个元素。对于任意a<b,up(a)与down(b)的交集都只有一个元素。
若要对[a,b]内的元素进行+n操作,只要down(a-1)的元素-n, down(b)的元素+n就好了。
设a<=c<=b,查询c时则对up(c)进行求和。因为up(c)与down(b)只有一个共同元素,所以可以完整的
体现修改。以上是一维的情况。可以非常直接的推论到二维。只要对x, y坐标同时up或down。理解了
上面的思路,这题就迎刃而解了。
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
1: const int N = 1001 ;
2:
3: int tree[N][N] = {0} ;
4:
5: //此过程是向上求的,不同于标准向下求
6: int GetSum( int n, int x, int y )
7: {
8: int y1 ;
9: int sum = 0 ;
10: while( x<=n ) //***
11: {
12: y1 = y ;
13: while( y1<=n )
14: {
15: sum += tree[x][y1] ;
16: y1 += ( y1 & -y1 ) ; //***
17: }
18: x += ( x & -x ) ;
19: }
20: return sum ;
21: }
22:
23: //此过程是向下求的,不同于标准向上求
24: void AddVal( int x, int y, int val )
25: {
26: int y1 ;
27: while( x>0 ) //***
28: {
29: y1 = y ;
30: while( y1>0 )
31: {
32: tree[x][y1] += val ;
33: y1 -= ( y1 & -y1 ) ; //***
34: }
35: x -= ( x & -x ) ;
36: }
37: }
38:
39: void run2155()
40: {
41: int caseNum,n,t ;
42: char c ;
43: int x1,y1,x2,y2 ;
44: int i ;
45:
46: scanf( "%d" , &caseNum ) ;
47: while( caseNum-- )
48: {
49: scanf( "%d%d", &n,&t ) ;
50:
51: memset(tree,0,sizeof(tree)) ; //对数组赋值
52:
53: while( t-- )
54: {
55: scanf( "\n%c", &c ) ;
56: if( c=='C' )
57: {
58: scanf( "%d%d%d%d", &x1,&y1,&x2,&y2 ) ;
59: AddVal( x2, y2, 1 ) ;
60: AddVal( x1-1, y2, -1 ) ;
61: AddVal( x2, y1-1, -1 ) ;
62: AddVal( x1-1, y1-1, 1 ) ;
63: }
64: else
65: {
66: scanf( "%d%d", &x1,&y1 ) ;
67: printf( "%d\n", GetSum(n,x1,y1)%2 ) ;
68: }
69: }
70: printf("\n") ;
71: }
72: }