首页 > 代码库 > 学习笔记——二维树状数组

学习笔记——二维树状数组

不知道为什么,就是想把这个坑给填了。。。

二维树状数组,本质上还是树状数组,只是在一维的基础上变成了二维。。。

单点修改  1到i,j查询和一维基本一样,直接上代码

技术分享
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define N 3010
using namespace std;
int a[N][N],n;
inline int lowbit(int x){
    return x&-x;
}
inline add(int x,int y,int del){
    for(int i=x;i<=n;i+=lowbit(i))
        for(int j=y;j<=n;j+=lowbit(j))
            a[i][j]+=del; 
}
inline sum(int x,int y){
    int num=0;
    for(int i=x;i;i-=lowbit(i))
        for(int j=y;j;j-=lowbit(j))
            num+=a[i][j];
    return num;
}
inline void Jimmy(){
}
int main(){
    Jimmy();
    return 0;
} 
二维树状数组 单点修改 1到i,j查询

下面介绍一下区间修改和区间查询

定义bi,j表示i,j到n,n的修改量,实质是一个标记,在计算sigma时我们通过统计区间内标记个数得出区间修改量之和

我们设面积前缀和S

那么S(x,y)=sigma(i<=x and j<=y) ai,j +sigma(i<=x and j<=y) bi,j*(x-i+1)*(y-j+1)

     =sigma(i<=x and j<=y) ai,j +sigma(i<=x and j<=y) bi,j*(x+1)*(y+1)-sigma(i<=x and j<=y) bi,j*i*(y+1)-sigma(i<=x and j<=y) bi,j*j*(x+1)+sigma(i<=x and j<=y) bi,j*i*j

所以我们维护四个数组 bi,j  bi,j*i  bi,j*j  bi,j*i*j  就可以在logn时间内来完成查询了

区间修改呢,就是在矩形的四个角分别打上标记

x1,y1 +del
x2+1,y1 -del
x1,y2+1 -del
x2+1,y2+1 +del

每个标记修改4个数组,一共16次

然后就ok啦

技术分享
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define N 3010
using namespace std;
int c1[N][N],c2[N][N],c3[N][N],c4[N][N],a[N][N],n,a[N][N],sum_[N][N];
inline int S(int x,int y){
    int num=sum_[x][y];
    for(int i=x;i;i-=lowbit(i))
        for(int j=y;j;j-=lowbit(j))
            num=num+c1[i][j]*(x+1)*(y+1)-c2[i][j]*(y+1)-c3[i][j]*(x+1)+c4[i][j];
    return num;
}
inline void change(int x,int y,int del){
    for(int i=x;i<=n;i+=lowbit(i))
        for(int j=y;j<=n;j+=lowbit(j)){
            c1[i][j]=c1[i][j]+del;
            c2[i][j]=c2[i][j]+del*i;
            c3[i][j]=c3[i][j]+del*j;
            c4[i][j]=c4[i][j]+del*i*j;
        }
}
inline int sum(int x1,int y1,int x2,int y2){
    return S(x2,y2)-S(x2,y1-1)-S(x1-1,y2)+S(x1-1,y1-1);
}
inline void add(int x1,int y1,int x2,int y2,int del){
    change(x1,y1,del);
    change(x1,y2+1,-del);
    change(x2+1,y1,-del);
    change(x2+1,y2+1,del);
}
inline void Jimmy(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)    
        for(int j=1;j<=n;j++)
            scanf("%d%d",&a[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            sum_[i][j]=sum_[i-1][j]+sum_[i][j-1]+a[i][j]-sum_[i][j];
}
int main(){
    Jimmy();
    return 0;
}
二维树状数组 区间修改 区间查询

学习来源:http://tonyfang.is-programmer.com/posts/206991.html

orzTonyFang

但是方老师原来的公式写错了,公式看这篇,代码正确性不是很保证,欢迎指出BUG

学习笔记——二维树状数组