【原】 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: }
原文地址:https://www.cnblogs.com/allensun/p/1870107.html