二維樹狀陣列-poj2155

u010660276發表於2013-12-09
Language:
Matrix
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 15922   Accepted: 6004

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) 對矩陣裡的某個數加上一個整數(可正可負) 
2) 查詢某個子矩陣裡所有數字的和,要求對每次查詢,輸出結果。   
一維樹狀陣列很容易擴充套件到二維,在二維情況下:陣列A[][]的樹狀陣列定義為: 
  
C[x][y] = ∑a[i][j], 其中, 
x-lowbit(x) + 1 <= i <= x, 
y-lowbit(y) + 1 <= j <= y. 

例:舉個例子來看看C[][]的組成。 
設原始二維陣列為: 
A[][]={{a11,a12,a13,a14,a15,a16,a17,a18,a19},   
       {a21,a22,a23,a24,a25,a26,a27,a28,a29}, 
       {a31,a32,a33,a34,a35,a36,a37,a38,a39}, 
       {a41,a42,a43,a44,a45,a46,a47,a48,a49}}; 
那麼它對應的二維樹狀陣列C[][]呢?   
記: 
    B[1]={a11,a11+a12,a13,a11+a12+a13+a14,a15,a15+a16,...} 這是第一行的一維樹狀陣列 
    B[2]={a21,a21+a22,a23,a21+a22+a23+a24,a25,a25+a26,...} 這是第二行的一維樹狀陣列 
    B[3]={a31,a31+a32,a33,a31+a32+a33+a34,a35,a35+a36,...} 這是第三行的一維樹狀陣列 
    B[4]={a41,a41+a42,a43,a41+a42+a43+a44,a45,a45+a46,...} 這是第四行的一維樹狀陣列 
那麼: 
  C[1][1]=a11,C[1][2]=a11+a12,C[1][3]=a13,C[1][4]=a11+a12+a13+a14,c[1][5]=a15,C[1][6]=a15+a16,... 
這是A[][]第一行的一維樹狀陣列 
  
C[2][1]=a11+a21,C[2][2]=a11+a12+a21+a22,C[2][3]=a13+a23,C[2][4]=a11+a12+a13+a14+a21+a22+a23+a24, 
C[2][5]=a15+a25,C[2][6]=a15+a16+a25+a26,... 
這是A[][]陣列第一行與第二行相加後的樹狀陣列 
  
C[3][1]=a31,C[3][2]=a31+a32,C[3][3]=a33,C[3][4]=a31+a32+a33+a34,C[3][5]=a35,C[3][6]=a35+a36,... 
這是A[][]第三行的一維樹狀陣列 
  
C[4][1]=a11+a21+a31+a41,C[4][2]=a11+a12+a21+a22+a31+a32+a41+a42,C[4][3]=a13+a23+a33+a43,... 
這是A[][]陣列第一行+第二行+第三行+第四行後的樹狀陣列   
搞清楚了二維樹狀陣列C[][]的規律了嗎? 仔細研究一下,會發現: 
(1)在二維情況下,如果修改了A[i][j]=delta,則對應的二維樹狀陣列更新函式為: 
 private void Modify(int i, int j, int delta){
         
         A[i][j]+=delta;
     
       for(int x = i; x< A.length; x += lowbit(x))
        for(int y = j; y <A[i].length; y += lowbit(y)){
          C[x][y] += delta;
        
        }
     }


(2)在二維情況下,求子矩陣元素之和∑ a[i][j](前i行和前j列)的函式為
    int Sum(int i, int j){
      int result = 0;
      for(int x = i; x > 0; x -= lowbit(x)) {
        for(int y = j; y > 0; y -= lowbit(y)) {
            result += C[x][y];
        }
      }
    return result;
   }
比如:
    Sun(1,1)=C[1][1];  Sun(1,2)=C[1][2]; Sun(1,3)=C[1][3]+C[1][2];...
    Sun(2,1)=C[2][1];  Sun(2,2)=C[2][2]; Sun(2,3)=C[2][3]+C[2][2];...
    Sun(3,1)=C[3][1]+C[2][1]; Sun(3,2)=C[3][2]+C[2][2];
轉化為樹狀陣列的方法便是:01矩陣初始化為0,對於置反操作,等價於將小矩形塊的四角置反(以此表示這四角代表的矩形塊被執行置反),於是我們對於置反操作,只操作四角的即可(可以累加操作次數,也可以單純的模擬置反操作,此時可利用bool陣列),然後對於詢問,只統計其左上方的矩陣元素的和(累加)奇偶情況,奇數說明最終置1,否則置0。
注意修改函式add只是對於[i][j]以及其後的點起作用,而我們統計的時候顯然是不把自身統計在內的,所以對於子矩形塊終點
[c][d],要分別++,這樣就可避免統計的時候把自己算在內

程式碼如下:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=1005;
int N,T;
int A[MAX][MAX];
void update(int i,int j,int num)
{
    while(i<=N)
    {
        int tmp=j;
        while(tmp<=N)
        {
            A[i][tmp]+=num;
            tmp+=tmp&(-tmp);
        }
        i+=i&(-i);
    }
}
int sum(int x,int y)
{
    int cnt=0;
    while(x>0)
    {
        int tmp=y;
        while(tmp>0)
        {
            cnt+=A[x][tmp];
            tmp-=tmp&(-tmp);
        }
        x-=x&(-x);
    }
    return cnt;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int X;
    cin>>X;
    char x;
    int x1,y1,x2,y2;
    while(X--)
    {
        cin>>N>>T;
        memset(A,0,sizeof(A));
        for(int i=0;i<T;i++)
        {
            cin>>x;
            if(x=='C')
            {
                cin>>x1>>y1>>x2>>y2;
                x2++;
                y2++;
                update(x1,y1,1);
                update(x1,y2,-1);
                update(x2,y1,-1);
                update(x2,y2,1);
            }
            else
            {
                cin>>x1>>x2;
                cout<<sum(x1,x2)%2<<endl;
            }
        }
        cout<<endl;
    }
    return 0;
}


相關文章