二维树状数组——SuperBrother打鼹鼠(Vijos1512)
树状数组(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)的更多相关文章
- 二维树状数组 BZOJ 1452 [JSOI2009]Count
题目链接 裸二维树状数组 #include <bits/stdc++.h> const int N = 305; struct BIT_2D { int c[105][N][N], n, ...
- HDU1559 最大子矩阵 (二维树状数组)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1559 最大子矩阵 Time Limit: 30000/10000 MS (Java/Others) ...
- POJMatrix(二维树状数组)
Matrix Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 22058 Accepted: 8219 Descripti ...
- poj 1195:Mobile phones(二维树状数组,矩阵求和)
Mobile phones Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 14489 Accepted: 6735 De ...
- 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 ...
- POJ 2155 Matrix(二维树状数组+区间更新单点求和)
题意:给你一个n*n的全0矩阵,每次有两个操作: C x1 y1 x2 y2:将(x1,y1)到(x2,y2)的矩阵全部值求反 Q x y:求出(x,y)位置的值 树状数组标准是求单点更新区间求和,但 ...
- [poj2155]Matrix(二维树状数组)
Matrix Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 25004 Accepted: 9261 Descripti ...
- POJ 2155 Matrix (二维树状数组)
Matrix Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 17224 Accepted: 6460 Descripti ...
- [POJ2155]Matrix(二维树状数组)
题目:http://poj.org/problem?id=2155 中文题意: 给你一个初始全部为0的n*n矩阵,有如下操作 1.C x1 y1 x2 y2 把矩形(x1,y1,x2,y2)上的数全部 ...
随机推荐
- [五]SpringMvc学习-Restful风格实现
1.Restful风格的资源URL 无后缀资源的访问(csdn用法) 2.SpringMvc对Rest风格的支持 2.1将 /*.do改为/ 2.2 3.@PathVariable获取Url变量 @R ...
- flash Timer类使用
var timer:Timer = new Timer(1000); timer.addEventListener("timer",tracerTimer); function t ...
- thinkPHP配置项
'URL_PATHINFO_DEPR'=>'-',//修改URL的分隔符 'TMPL_L_DELIM'=>'<{', //修改左定界符 'TMPL_R_DELIM'=>'}&g ...
- GridView控件显示图片
与图片的二进制数据库存储和显示 1.将图片以二进制存入数据库 2.读取二进制图片在页面显示 3.设置Image控件显示从数据库中读出的二进制图片 4.GridView中ImageField以URL方式 ...
- ShowcaseView-master
ShowcaseView.rar
- Android 多点手势识别详解
google 提供的API中,有个类,大家都很熟悉,GestureDetector.使用它,我们可以识别用户通常会用的手势.但是,这个类不支持多点触摸(可能 google认为没有人会在几个手指都在屏幕 ...
- oracle之单行函数
单行函数 ①.字符函数 LOWER(x):将x中的每一个单词都转换成小写 UPPER(x):将x中的每一个单词都转换成大写 INITCAP(x): 将x中的每一个单词的首字母转换成大写 CONC ...
- Codeforces 444C DZY Loves Colors(线段树)
题目大意:Codeforces 444C DZY Loves Colors 题目大意:两种操作,1是改动区间上l到r上面德值为x,2是询问l到r区间总的改动值. 解题思路:线段树模板题. #inclu ...
- HttpClient 4.3.* 上传带中文文件名文件文件名乱码问题的解决
又是折腾了一天才解决的问题,网上关于这个问题的资料不多,希望写出来能帮到有需要的人. 之前无论怎么设置charset都不起作用, 后来看了这篇文章 才发现MultipartEntityBuilder有 ...
- 应聘.net开发工程师常见的面试题(五)
1.描述一下C#中索引器的实现过程,是否只能根据数字进行索引? 答:不是.可以用任意类型. 2.在C#中,string str = null 与 string str = ” ” 请尽量使用文字或图象 ...