POJ-2155(二维树状数组)

这篇博客介绍了如何理解并应用二维树状数组,通过解决POJ-2155问题来阐述其基本思想。在二维树状数组中,c[i][j]表示矩阵a[i-lowbit[i]+1][j-lowbit[j]+1]到a[i][j]的元素之和。博客解释了二维树状数组的操作,包括翻转区间和查询特定点的翻转次数,将一维概念扩展到二维情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:http://poj.org/problem?id=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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值