1. 程式人生 > >POJ 1195 Mobile phones(二維樹狀數組)

POJ 1195 Mobile phones(二維樹狀數組)

給定 ostream 題意 == turn += ret 一個 合成

題目鏈接:POJ 1195

題意:

  給出一個S*S的矩陣(行、列號從1開始),每個元素初始值為0,有兩種操作:一種是第X行第Y列元素值加A;另一種是查詢給定範圍矩陣的所有元素之和(L<=X<=R,B<=Y<=T)。

分析:

  查詢給定範圍矩陣的所有元素之和是二維區間和,可以轉換為二維前綴和求值。類比一維前綴和求法,二維區間和S(L, B, R, T) = S(1, 1, R, T) - S(1 ,1, L-1, T) - S(1, 1, R, B-1) + S(1, 1, L-1, B-1)。單點更新一個元素的值,修改二維前綴和,類比一維樹狀數組的更新操作,二維樹狀數組的更新操作(參考代碼)。

總結:

  二維樹狀數組可以理解為:先固定X=i,把Y=1~S看作一維樹狀數組就比較容易理解,再X=1~S看作一維樹狀數組,這樣組合成二維樹狀數組。如果還想不明白,可以想想二元積分是怎麽做的。

代碼實現:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int N = 1024 + 5;
int C[N][N], cmd, s, x, y, a, l, b, r, t;

int lowbit(int x)
{
    return x & (-x);
}
void add(int x, int y, int a)
{
    for (int i = x; i <= s; i += lowbit(i))
        for (int j = y; j <= s; j += lowbit(j))
            C[i][j] += a;
}
int sum(int x, int y)
{
    int ret = 0;
    for (int i = x; i; i -= lowbit(i))
        for (int j = y; j; j -= lowbit(j))
            ret += C[i][j];
    return ret;
}
int main()
{
    while (~scanf("%d", &cmd)) {
        if (cmd == 3) break;
        if (cmd == 0) {
            scanf("%d", &s);
            for (int i = 1; i <= s; i++)
                for (int j = 1; j <= s; j++)
                    C[i][j] = 0;
            continue;
        }
        if (cmd == 1) {
            scanf("%d%d%d", &x, &y, &a);
            x++, y++;
            add(x, y, a);
            continue;
        }
        if (cmd == 2) {
            scanf("%d%d%d%d", &l, &b, &r, &t);
            l++, b++, r++, t++;
            int ans = sum(r, t) - sum(l-1, t) - sum(r, b-1) + sum(l-1, b-1);
            printf("%d\n", ans);
        }
    }
    return 0;
}

  

POJ 1195 Mobile phones(二維樹狀數組)