我们来搞一个二维树状数组
首先初始数组还是a数组,二维的
搞一个b数组,也是二维,b[i][ ]就是a数组第i行的一维树状数组
b[2][1]=a[2][1];
b[2][2]=a[2][1]+a[2][2];
b[2][3]=a[2][3];
.......
最后我们来搞一个c数组,当然它还是二维的hhh
c[1][ ]就是第一行的树状数组,c[2][ ]是第一行加第二行,c[3][ ]是第三行,c[4][ ]就是前四行之和......
c[i][j]=i管理的树状数组中j项的和
看懂了么?其实就是在b数组的基础上,给b数组建了一个树状数组
a数组(初始数组)
2 | 1 | 3 | 4 |
1 | 5 | 4 | 3 |
5 | 2 | 5 | 4 |
b数组(a数组的树状数组)
2 | 3 | 3 | 10 |
1 | 6 | 4 | 13 |
5 | 7 | 5 | 16 |
c数组(b数组的树状数组)
2 | 3 | 3 | 10 |
3 | 9 | 7 | 23 |
5 | 7 | 5 | 16 |
模拟一下单点修改
假如给a[1][2]+2;
a数组(初始数组)
2 | 3 | 3 | 4 |
1 | 5 | 4 | 3 |
5 | 2 | 5 | 4 |
b数组(a数组的树状数组)
2 | 5 | 3 | 12 |
1 | 6 | 4 | 13 |
5 | 7 | 5 | 16 |
c数组(b数组的树状数组)
2 | 5 | 3 | 12 |
3 | 11 | 7 | 25 |
5 | 7 | 5 | 16 |
这就是二维树状数
组的修改过程,我们发现,c数组只有c[1][2],c[1][4],c[2][2],c[2][4]改变了,其实就是……怎么说呢,就是c数组的横坐标和纵坐标分别作为一个树状数组来看……(越绕越乱,自行理解)
如果没看懂,那就直接上代码吧
(其实我现在稍微有点懵,写完代码应该就懂了)
#include<iostream>
using namespace std;
int a[10100][10100],b[10100][10100],c[10100][10100],n,m,k;
int lowbit(int x)
{
return x&-x;
}
void modifyb(int x,int y,int z)
{
for (int s=y;s<=m;s+=lowbit(s))
b[x][s]+=z;
}
void modifyc(int x,int y,int z)
{
for (int s=y;s<=n;s+=lowbit(s))
c[s][x]+=z;
}
void modify(int x,int y,int z)
{
for (int s=x;s<=n;s+=lowbit(s))
for (int o=y;o<=m;o+=lowbit(o))
c[s][o]+=z;
}
int query(int x,int y)
{
int ans=0;
for (int s=x;s>0;s-=lowbit(s))
for (int o=y;o>0;o-=lowbit(o))
ans+=c[s][o];
return ans;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
modifyb(i,j,a[i][j]);
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++)
modifyc(i,j,b[j][i]);
for (int i=1;i<=k;i++)
{
int p;
scanf("%d",&p);
if (p==1)
{
int Q,w,q;
scanf("%d%d%d",&Q,&w,&q);
modify(Q,w,q);
}
if (p==2)
{
int w,q,W,Q,anss;
scanf("%d%d%d%d",&w,&q,&W,&Q);
anss=query(W,Q)+query(w-1,q-1)-query(W,q-1)-query(w-1,Q);
printf("%d\n",anss);
}
}
return 0;
}
那么树状数组就彻底告一段落了
至此,已经解决了:树状数组单点修改区间查询,树状数组区间修改单点查询,树状数组区间修改区间查询,二维树状数组
树状数组大法好!!!