您的位置:首页 > 其它

从一维树状数组到二维树状数组

2018-02-11 10:49 281 查看
上一篇讲的是一维数组的树状数组,可以实现“单点修改,区间查询”,“区间修改,单点查询”,“区间修改,区间查询”。
今天接触二维树状数组。
其实,要明确的一点是,不管是一维还是二维树状数组,都只是工具而已,只是帮助我们更快地求和,查询,树状数组的这些操作都可以用我们平常的方法求,例如一直加。
面对一个二维数组,我们要求它们的和,会怎么做呢?
先求出第一行的总和
再求出第二行的总和
再求出第三行的总和
..........
求出最后一行的总和
最后就是每一行都加起来,得出来的就是二维数组的总和。
那我们用树状数组来帮我们 “算快一点” 呢?
第一行是一个树状数组,区间求和
第二行是一个树状数组,区间求和
第三行是一个树状数组,区间求和
..........
最后一行也是树状数组,区间求和
假如有 100000 行呢?
那我们把每一行树状数组当做一个值,变成一列,对这一列求和,那不就变成一个一维树状数组了吗int sum( int x , int y ){
int _y = y ;
LL ans = 0 ;
while( x ){
_y = y ;
while( _y ){
ans += c[x][_y] ;
_y -= lower( _y ) ;
}
x -= lower( x ) ;
}
return ans ;
}这是对  1- x , 1-y 所表示的矩阵的求和函数,就是嵌套的一维求和呢
换个方式看LL sum( int *c , int x ){
LL ans = 0 ;
while( x ){
ans += c[x] ; // 每一行求和
x -= lower( x ) ;
}
return ans ;
}

int Matrix_sum( int x , int y ){
LL ans = 0 ;
while( x ){
ans += sum( c[x] , y ) ; // 所有行当做一列,对这一列求和
x -= lower( x ) ;
}
return ans ;
}应该很清楚了吧更新操作一样的,也都是一维树状数组的更新,然后每一行再看做一列,还是一维更新void update( int x , int y , int add ){
int _y = y ;
while( x <= N ){
_y = y ;
while( _y <= N ){
c[x][_y] += add ;
_y += lower( _y ) ;
}
x += lower( x ) ;
}
}换个方式看
void update( int *c , int x , int add ){
while( x <= N ){
c[x] += add ;
x += lower( x ) ;
}
}

void Matrix_update( int x , int y , int add ){
while( x <= N ){
update( c[x] , y , add ) ;
x += lower( x ) ;
}
}
其实都是我们正常对矩阵的求和操作,先求出每一行,再求这些行的总和。树状数组,线段树只是让我们求得更快而已。也就可以推广到三维,四维..... N 维,都是树状数组的嵌套。
贴一道例题:POJ 2155
对二维数组的求和,求出来的和,如果是偶数,说明被修改回来了,如果是奇数,说明没被改回来#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std ;
#define LL long long
#define lower(x) x&-x
int N , Q ;
int c[1002][1002] ;

void update( int x , int y , int add ){
int _y = y ;
while( x <= N ){
_y = y ;
while( _y <= N ){
c[x][_y] += add ;
_y += lower( _y ) ;
}
x += lower( x ) ;
}
}

int sum( int x , int y ){
int _y = y ;
LL ans = 0 ;
while( x ){
_y = y ;
while( _y ){
ans += c[x][_y] ;
_y -= lower( _y ) ;
}
x -= lower( x ) ;
}
return ans & 1 ;
}

int main(){
int cases , x1 , y1 , x2 , y2 ;
scanf( "%d" , &cases ) ;
while( cases-- ){
memset( c , 0 , sizeof( c ) ) ;
scanf( "%d%d" , &N , &Q ) ;
char opt[2] ;
while( Q-- ){
scanf( "%s" , opt ) ;
if( opt[0] == 'C' ){
scanf( "%d%d%d%d" , &x1 , &y1 , &x2 , &y2 ) ;
update( x1 , y1 , 1 ) ;
update( x1 , y2+1 , -1 ) ;
update( x2+1 , y1 , -1 ) ;
update( x2+1 , y2+1 , 1 ) ;
}
else{
scanf( "%d%d" , &x1 , &y1 ) ;
printf( "%d\n" , sum( x1 , y1 ) ) ;
}
}
if( cases ) printf( "\n" ) ;
}
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: