学习笔记——二维树状数组
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习笔记——二维树状数组相关的知识,希望对你有一定的参考价值。
不知道为什么,就是想把这个坑给填了。。。
二维树状数组,本质上还是树状数组,只是在一维的基础上变成了二维。。。
单点修改 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; }
下面介绍一下区间修改和区间查询
定义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
以上是关于学习笔记——二维树状数组的主要内容,如果未能解决你的问题,请参考以下文章