树状数组(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. Keil Mdk5.0 破解包 和谐包【worldsing笔记】

    有关Keil MDK 5.0的介绍和下载 http://www.cnblogs.com/worldsing/p/3355911.html 下载地址 点击下载:http://pan.baidu.com/ ...

  2. 简单dp-poj-2231-Moo Volume

    题目链接: http://poj.org/problem?id=2231 题目大意: 给n个位置,求所有位置到其他n-1个位置的距离总和. 解题思路: 简单dp. o(n^2)的时间复杂度会超.先对这 ...

  3. ios开发 数据库版本迁移手动更新迭代和自动更新迭代

    数据库版本迁移顾名思义就是在原有的数据库中更新数据库,数据库中的数据保持不变对表的增.删.该.查. 数据持久化存储: plist文件(属性列表) preference(偏好设置) NSKeyedArc ...

  4. Central Authentication Service

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  5. hdu 5495 LCS 水题

    LCS Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5495 Descr ...

  6. [React Fundamentals] Component Lifecycle - Updating

    The React component lifecycle will allow you to update your components at runtime. This lesson will ...

  7. Java中的NIO和IO的对比分析

    总的来说,java中的IO和NIO主要有三点区别: IO NIO 面向流 面向缓冲 阻塞IO 非阻塞IO 无 选择器(Selectors) 1.面向流与面向缓冲 Java NIO和IO之间第一个最大的 ...

  8. 运维知识体系v0.5

    http://www.90qj.com/?post=318http://ixdba.blog.51cto.com/2895551/1751377   运维知识体系v0.5-(运维社区-赵班长出品,欢迎 ...

  9. android的项目文件介绍

    1.res目录存放Android的各种资源文件,比如layout存放布局文件main.xml,values存放各种xml格式的资源文件,字符串资源strings.xml,颜色资源文件:colors.x ...

  10. 六、Socket之UDP异步传输文件-实现稳定的文件传输

    上一篇文章五.Socket之UDP异步传输文件-实现传输中取消传送中,还遗留了一个传输文件最大的问题,就是传输过程中丢包,这样在文件传输过程中就会卡住了,这篇文章就来解决文件传输中的丢包问题,实现稳定 ...