树状数组(BIT)是一个查询和修改复杂度都为log(n)的数据结构,主要用于查询任意两位之间的所有元素之和,其编程简单,很容易被实现。而且可以很容易地扩展到二维。让我们来看一道很裸的二维树状数组题:

在一个“打鼹鼠”的游戏中,鼹鼠会不时地从洞中钻出来,不过不会从洞口钻进去(鼹鼠真胆大……)。洞口都在一个大小为n(n<=1024)的正方形中。这个正方形在一个平面直角坐标系中,左下角为(0,0),右上角为(n-1,n-1)。洞口所在的位置都是整点,就是横纵坐标都为整数的点。而SuperBrother也不时地会想知道某一个范围的鼹鼠总数。这就是你的任务。

  每个输入文件有多行。
    第一行,一个数n,表示鼹鼠的范围。
    以后每一行开头都有一个数m,表示不同的操作:
      m=1,那么后面跟着3个数x,y,k(0<=x,y<n),表示在点(x,y)处新出现了k只鼹鼠;
      m=2,那么后面跟着4个数x1,y1,x2,y2(0<=x1<=x2<n,0<=y1<=y2<n),表示询问矩形(x1,y1)-(x2,y2)内的鼹鼠数量;
      m=3,表示老师来了,不能玩了。保证这个数会在输入的最后一行。

    询问数不会超过10000,鼹鼠数不会超过maxlongint。

  把这个问题简单抽象一下。就是:

  • 输入1时,对一个二维矩阵中某个位置上加上一个数k。
  • 输入2时,求出矩阵中[(x1,y1);(x2,y2)]的子矩阵中,元素的总大小并输出。
  • 输入3时,退出。

  这个问题,输入数据规模可能很大(虽然实际上并非这样,出题人懒到随机生成数据)。而且是动态修改,显然不能使用前缀和,所以,树状数组就是我们的首选。而然,树状数组本来是一维的,如何把它推广到二维去呢。其实很简单,其方法类似与先生成没一行原数组的一维树状数组,再把一个个一维树状数组组合成二维的其对应关系为:

  C[1][1]=a[1][1],C[1][2]=a[1][1]+a[1][2],C[1][3]=a[1][3],C[1][4]=a[1][1]+a[1][2]+a[1][3]+a[1][4],c[1][5]=a[1][5],C[1][6]=a[1][5]+a[1][6],...

  C[2][1]=a[1][1]+a[2][1],C[2][2]=a[1][1]+a[1][2]+a[2][1]+a[2][2],C[2][3]=a[1][3]+a[2][3],C[2][4]=a[1][1]+a[1][2]+a[1][3]+a[1][4]+a[2][1]+a[2][2]+a[2][3]+a[2][4], C[2][5]=a[1][5]+a[2][5],C[2][6]=a[1][5]+a[1][6]+a[2][5]+a[2][6],...

  C[3][1]=a[3][1],C[3][2]=a[3][1]+a[3][2],C[3][3]=a[3][3],C[3][4]=a[3][1]+a[3][2]+a[3][3]+a[3][4],C[3][5]=a[3][5],C[3][6]=a[3][5]+a[3][6],...

  C[4][1]=a[1][1]+a[2][1]+a[3][1]+a[4][1],C[4][2]=a[1][1]+a[1][2]+a[2][1]+a[2][2]+a[3][1]+a[3][2]+a[4][1]+a[4][2],C[4][3]=a[1][3]+a[2][3]+a[3][3]+a[4][3],...(太多了,我就写到3吧)

  ……

  通过观察能发现,第一行是本身,第二行是第一行加上其本身,第三行是本身,第四行是第一、二行加上其本身。这和一维的树状数组是一摸一样的。所以,我们很容易就可以写出修改、查询 函数。

void modfily(int x,int y,int data){
x+=1;y+=1;
for (int i=x;i<=n;i+=lowbit(i))
for (int j=y;j<=n;j+=lowbit(j))
c[i][j]+=data;
}
int sum(int x,int y){
x+=1;y+=1;
int result=0;
for (int i=x;i>0;i-=lowbit(i))
for (int j=y;j>0;j-=lowbit(j))
result+=c[i][j];
return result;
}

  这就是二维树状数组的核心了,代码和一维的相仿,异常简单。大家可能有疑问,为什么i,j要加1。其实这是我被坑以后的领悟,如果i,j=0的话,lowbit也永远为0,程序会陷入死循环,直接TLE。从这两个函数我们也可以看出,二维树状数组的查询、修改时间复杂度为log(n)²。

  数据结构部分解决了,怎么求一个子矩阵中的数的和呢?画张图我们就可以求出,公式为:sum(x2, y2) - sum(x1-1, y2) - sum(x2, y1-1) + sum(x1-1, y1-1)

  顺便附上这道例题的AC code:

#include <cstdio>
#include <cstdlib>
using namespace std; int m=0,n,x,y,k,x1,y1,c[1026][1026];
void modfily(int,int,int);
int sum(int,int);
inline int lowbit(int x){
return x&(-x);
} int main(void){
scanf("%d",&n);
for (int i=0;i<n;++i)
for (int j=0;j<n;++j) c[i][j]=0;
while (m!=3){
scanf("%d",&m);
if (m==1){
scanf("%d%d%d",&x,&y,&k);
modfily(x,y,k);
}
if (m==2){
scanf("%d%d%d%d",&x,&y,&x1,&y1);
printf("%d\n",abs(sum(x1,y1)-sum(x-1,y1)-sum(x1,y-1)+sum(x-1,y-1)));
}
}
return 0;
}
void modfily(int x,int y,int data){
x+=1;y+=1;
for (int i=x;i<=n;i+=lowbit(i))
for (int j=y;j<=n;j+=lowbit(j))
c[i][j]+=data;
}
int sum(int x,int y){
x+=1;y+=1;
int result=0;
for (int i=x;i>0;i-=lowbit(i))
for (int j=y;j>0;j-=lowbit(j))
result+=c[i][j];
return result;
}

  

二维树状数组——SuperBrother打鼹鼠(Vijos1512)的更多相关文章

  1. 二维树状数组 BZOJ 1452 [JSOI2009]Count

    题目链接 裸二维树状数组 #include <bits/stdc++.h> const int N = 305; struct BIT_2D { int c[105][N][N], n, ...

  2. HDU1559 最大子矩阵 (二维树状数组)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1559 最大子矩阵 Time Limit: 30000/10000 MS (Java/Others)  ...

  3. POJMatrix(二维树状数组)

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 22058   Accepted: 8219 Descripti ...

  4. poj 1195:Mobile phones(二维树状数组,矩阵求和)

    Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14489   Accepted: 6735 De ...

  5. Codeforces Round #198 (Div. 1) D. Iahub and Xors 二维树状数组*

    D. Iahub and Xors   Iahub does not like background stories, so he'll tell you exactly what this prob ...

  6. POJ 2155 Matrix(二维树状数组+区间更新单点求和)

    题意:给你一个n*n的全0矩阵,每次有两个操作: C x1 y1 x2 y2:将(x1,y1)到(x2,y2)的矩阵全部值求反 Q x y:求出(x,y)位置的值 树状数组标准是求单点更新区间求和,但 ...

  7. [poj2155]Matrix(二维树状数组)

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 25004   Accepted: 9261 Descripti ...

  8. POJ 2155 Matrix (二维树状数组)

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17224   Accepted: 6460 Descripti ...

  9. [POJ2155]Matrix(二维树状数组)

    题目:http://poj.org/problem?id=2155 中文题意: 给你一个初始全部为0的n*n矩阵,有如下操作 1.C x1 y1 x2 y2 把矩形(x1,y1,x2,y2)上的数全部 ...

随机推荐

  1. AVR ISP

    1.ISP下载说明: 2.配置时钟熔丝: 时钟不可乱配置,最好是内部或是外部晶震,配置成其它的有可能会锁死ISP,如果锁死只能用外加时钟(8MHz以下的)才可以ISP,M8没有Jtag.

  2. Unity3D之AssetBundle学习:Android上运行笔记

    路径统一 在Android上加载StreamingAssets文件夹下的AssetBundle文件,首先需要对加载地址进行处理,注意PC.Android和IOS的地址不一致需要针对不同的平台不同的处理 ...

  3. 如何在线缩小jpg图片的大小

    直接使用在线PS保存成更小格式,即可! 在线PS网址:http://www.webps.cn/ 打开图片 点击保存 直接拖动滑动条就可以改变图片大小

  4. Win8.1激活

    激活查询:在桌面状态下输入“Win+R”,进入运行栏目,输入slmgr.vbs -dlv 显示:最为详尽的激活信息,包括:激活ID.安装ID.激活截止日期 http://www.nruan.com/w ...

  5. 设置UITabBarController的背景颜色

    if (IOS7) { self.tabBarController.tabBar.barTintColor = kTAB_BAR_GB_COLOR; }else{ self.tabBarControl ...

  6. linux-insides-cn-BOOK

    https://www.gitbook.com/book/xinqiu/linux-insides-cn/details https://www.gitbook.com/book/looly/elas ...

  7. javascript之css常用属性

    1. position : 属性值有absolute .fixed.relative absolute:生成绝对定位的元素,相对第一父元素进行定位: fixed :   生成绝对定位的元素,相对于浏览 ...

  8. C#_MVC_Repository_CURD_Controller

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  9. Android ADB启动失败 ADB server out of date

    调试Android程序时总提示ADB未运行,转到命令行方式下启动ADB, adb kille-server停止ADB, 然后再运行adb start-server 随后提示: adb server i ...

  10. -----------------------------SpringMVC理解-----------------------------

    1.用户发送请求到前端控制器(DispatcherServlet); 2.前端控制器转发请求到处理器映射器(HandlerMapping): 3.处理器映射器将拦截的Action返回到前端控制器: 4 ...