数据结构----树状数组----二维区间的修改与查询

一、二维树状数组(如果不知道树状数组,请点这里)

先来看一下一维的树状数组的结构:


其实二维树状数组也差不多,只不过每一行和每一列都是一个树状数组,画出来就有些眼花缭乱了,在这里就不画出来了,先把getsum()和update()的代码写出来吧。

getsum():

int lowbit(int x)
{
    return x&-x;
}
int getsum2(int x,int y)
{
    int sum=0,i,j;
    for(i=x;i>0;i-=lowbit(i)){
        for(j=y;j>0;j-=lowbit(j)){
            sum+=treearray[i][j];
        }
    }
    return sum;
}
update():

void update2(int x,int y,int d)
{
    for(int i=x;i<=N;i+=lowbit(i)){
        for(int j=y;j<=N;j+=lowbit(j)){
            treearray[i][j]+=d;
        }
    }
}
可以看出二维树状数组和一维树状数组在代码之间是比较相似的。


来看一道例题:

二、题目描述

二维区间的和

假定在 Tampere 地区的第四代移动电话基站这样运行:整个地区分成方块,方块形成 S×S 矩阵,行和列编号从 0 S-1. 每个方块包含一个基站。在每个方块中的活动移动电话数可以改变,因为电话能从一个方块移动到另一个方块,或者电话能开机或关机。每过一段时间,每个基站都向主站报告自身活动电话的改变情况,以及自己在矩阵中的行列位置。
写一个程序,能够接收这些基站的报告,并回答关于指定矩形区域内的活动移动电话数量的询问。

输入

由若干行组成,每行由一个指令字 ( 整数 ) 和一些整数参数组成。指令字含义为:
指令 参数 意义
0 S  初始化 S*S  的区域为全 0 ,该指令仅在开头出现一次。(1<=S<=1500)
1 X Y A  在方块 (X,Y) 处加上 A 个活动移动电话, A 可为正可为负。
L  B R T  询问各个方块中活动移动电话的数量之和, L ≤ X ≤ R, B ≤ Y ≤ T
结束程序,该指令仅在结束时出现一次。
保证数据在给定范围内,不必检验。如果 A 是负数 可以保证不会使某个方块的值减小为负数。下标从 0 开始,也就是说,对于  4×4  的区域  0 ≤ X ≤ 3   0 ≤ Y ≤ 3

输出

对每一个指令字为2的输入,在一行上回答一个询问

样例输入

0 4
1 1 2 3
2 0 0 2 2
1 1 1 2
1 1 2 -1
2 1 1 2 3
3

样例输出

3
4


这道题其实就是一个二维树状数组的应用,很简单,直接上代码:

#include<cstdio>
#include<cstring>
int treearray[1502][1502],N;
int lowbit(int x)
{
    return x&-x;
}
int getsum2(int x,int y)
{
    int sum=0,i,j;
    for(i=x;i>0;i-=lowbit(i)){
        for(j=y;j>0;j-=lowbit(j)){
            sum+=treearray[i][j];
        }
    }
    return sum;
}
void update2(int x,int y,int d)
{
    for(int i=x;i<=N;i+=lowbit(i)){
        for(int j=y;j<=N;j+=lowbit(j)){
            treearray[i][j]+=d;
        }
    }
}
int main()
{
    int o,x,y,z,w,d;
    while(1){
        scanf("%d",&o);
        if(o==0) scanf("%d",&N);
        else if(o==3) break;
        else if(o==1){scanf("%d%d%d",&x,&y,&d);update2(x+1,y+1,d);}
        else if(o==2){scanf("%d%d%d%d",&x,&y,&z,&w);printf("%d\n",getsum2(z+1,w+1)-getsum2(x,w+1)-getsum2(z+1,y)+getsum2(x,y));}
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值