1. 程式人生 > >poj2155 Matrix(經典二維樹狀陣列)

poj2155 Matrix(經典二維樹狀陣列)

吐槽:這題先說[x1,y1]和[x2,y2]是左上角和右下角的兩個點,又說x1<=x2&&y1<=y2,那就是x軸向右,y軸向下為正方向。mdzz啊,座標系這種東西能不能標準一下= =,這裡我們就按照左下角和右上角來了。

題意:輸入n*n矩陣,有兩個操作,C代表翻轉[x1,y1]到[x2,y2]矩陣內的值(0變1,1變0),Q代表查詢某點的值。

思路:和普通的單點更新和求和不同,這裡是區間更新和單點求值。重點在於翻轉操作,矩陣大操作多肯定不能一個一個翻。看懂這個是關鍵。

這篇部落格把二進位制中的區間更新變為了邊界更改,也是二進位制所特有的,剛開始死活看不懂,這nmsjbwya,後來紙上模擬一下,什麼都懂了。

某點的翻轉次數變為了求1~x的和,二進位制中對邊界的更改體現到了區間上,然後模2得出值。只能說我表達不清,絕知此事要躬行吧= =

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <math.h>

using namespace std;

typedef long long ll;
const int N = 1005;

int tree[N][N], n;//從當前元素開始連續往左求lowbit(x)個數的和

int lowbit(int x)
{
    return -x&x;
}

void update(int i, int j, int val)
{
    while(i <= n)
    {
        int tmp = j;
        while(tmp <= n)
        {
            tree[i][tmp]+=val;
            tmp+=lowbit(tmp);
        }
        i+=lowbit(i);
    }
}

int sum(int i, int j)
{
    int num = 0;
    while(i > 0)//說明還有組可加
    {
        int tmp = j;
        while(tmp > 0)
        {
            num+=tree[i][tmp];
            tmp-=lowbit(tmp);
        }
        i-=lowbit(i);
    }
    return num;
}

int main()
{
   // freopen("in.txt", "r", stdin);
    int X, t, x, y, x1, y1, x2, y2, flag = 0;
    char op[5];
    scanf("%d", &X);
    while(X--)
    {
        if(flag) printf("\n");
        flag = 1;
        scanf("%d%d", &n, &t);
        memset(tree, 0, sizeof(tree));
        for(int i = 1; i <= t; i++)
        {
            scanf("%s", op);
            if(op[0] == 'C')
            {
                scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
                update(x1, y1, 1);
                update(x1, y2+1, 1);
                update(x2+1, y1, 1);
                update(x2+1, y2+1, 1);
            }
            else if(op[0] == 'Q')
            {
                scanf("%d%d", &x, &y);
                printf("%d\n", sum(x, y)%2);//從[1,1]到該點的和
            }
        }
    }
    return 0;
}