1. 程式人生 > >POJ-2155(二維樹狀陣列)

POJ-2155(二維樹狀陣列)

學習了這篇部落格的講解徹底弄懂二維樹狀陣列,做了二維樹狀陣列的第1題。

雖然是二維,但跟一維的思想基本相同,只不過一維時用C[i]表示a[i-lowbit[i]+1] ~ a[i]的和,二維時用c[i][j]表示a[i-lowbit[i]+1][j-lowbit[j]+1] ~ a[i][j]的和。

先來看一維的問題,則矩陣退化成線段,(x,y)點退化成x點,操作也變為C x y和Q x:

(1)對於C x y,即對[x,y]之間的所有點翻轉,相當於對[1,x-1]之間的所有點翻轉,再對[1,y]之間的所有點翻轉

(2)對於Q x,即查詢點x進行了多少次翻轉,由於y = x,y = y+lowbit(y),y = y+lowbit(y)都覆蓋了點x,所以我們只需對這些c[y]累加,即可得到x點的翻轉次數

將上述思想推廣到二維,則

(1)對於C a b c d,即對[a,b] -> [c,d]之間的所有點進行翻轉,相當於對[1,1] -> [a-1,d]之間的所有點進行翻轉,再對[1,1] -> [c,b-1]之間的所有點進行翻轉,再對[1,1] -> [a-1,b-1]之間的所有點進行翻轉,在對[1,1] -> [c,d]之間的所有點進行翻轉

(2)對於Q a b,即查詢點(a,b)進行了多少次翻轉,由於[x = a; y = b, y = y + lowbit(y), ... y = y + lowbit(y)]覆蓋了點(a,b),且[x = x + lowbit(x); y = b, y = y + lowbit(y), ..., y = y + lowbit(y)]覆蓋了點(a,b),以此類推。


#include <cstdio>
#include <cstring>
#define MAX 1024

int N, T, c[MAX][MAX] = {0};

inline int lowbit(int x){ return x & -x; }
void init()
{
    for(int i = 1; i <= N; ++i)
        memset(c[i] + 1, 0, N * sizeof(int));
}
void update(int i, int j)
{
    for(int x = i; x; x -= lowbit(x))
        for(int y = j; y; y -= lowbit(y))
            ++c[x][y];
}
int query(int i, int j)
{
    int sum = 0;
    for(int x = i; x <= N; x += lowbit(x))
        for(int y = j; y <= N; y += lowbit(y))
            sum += c[x][y];
    return sum;
}


int main()
{
    int test, a, b, c, d;
    char s[4];
    for(scanf("%d", &test); test--; ){
        scanf("%d%d", &N, &T);
        init();
        while(T--){
            scanf("%s%d%d", s, &a, &b);
            if(s[0] == 'C'){
                scanf("%d%d", &c, &d);
                update(c, b-1);
                update(a-1, d);
                update(a-1, b-1);
                update(c, d);
            }
            else puts(query(a, b) & 1 ?  "1" : "0");
        }
        puts("");
    }
    return 0;
}