题目链接:POJ 1195 Mobile phones
【题目大意】
如图所示,开始的操作为 0 初始化 S * S大小的地图,值为0
操作 1, 输入 X Y A, 将地图中坐标为 (X,Y)的值修改为A
操作2, 输入 L B R T 查询 区间 (X,Y) L<=X<=R , B<=Y<=T, 输出该矩形区间的和;
操作 3 结束程序
典型的二维树状数组
二维树状数组和一维树状数组原理是一样的。
我们先回顾一维树状数组 C【maxn】,
它的储存结构
C1 = A1
C2 = A1 + A2
C3 = A3
C4 = A1 + A2 + A3 + A4
C5 = A5
C6 = A5 + A6
C7 = A7
C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
……
C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
......
而二维树状数组的第二维 与普通一维树状数组原理是一样的
设二维树状数组为 C[][]
例:举个例子来看看C[][]的组成。
设原始二维数组为:
A[][]={{a11,a12,a13,a14,a15,a16,a17,a18,a19},
{a21,a22,a23,a24,a25,a26,a27,a28,a29},
{a31,a32,a33,a34,a35,a36,a37,a38,a39},
{a41,a42,a43,a44,a45,a46,a47,a48,a49}};
那么它对应的二维树状数组C[][]呢?
B[1]={a11,a11+a12,a13,a11+a12+a13+a14,a15,a15+a16,...} 这是第一行的一维树状数组
B[2]={a21,a21+a22,a23,a21+a22+a23+a24,a25,a25+a26,...} 这是第二行的一维树状数组
B[3]={a31,a31+a32,a33,a31+a32+a33+a34,a35,a35+a36,...} 这是第三行的一维树状数组
B[4]={a41,a41+a42,a43,a41+a42+a43+a44,a45,a45+a46,...} 这是第四行的一维树状数组
那么:
C[1][1]=a11,C[1][2]=a11+a12,C[1][3]=a13,C[1][4]=a11+a12+a13+a14,c[1][5]=a15,C[1][6]=a15+a16,...
这是A[][] 第一行 的一维树状数组
C[2][1]=a11+a21,C[2][2]=a11+a12+a21+a22,C[2][3]=a13+a23,C[2][4]=a11+a12+a13+a14+a21+a22+a23+a24,C[2][5]=a15+a25,C[2][6]=a15+a16+a25+a26,...
这是A[][]数组 第一行与第二行 相加后的树状数组
C[3][1]=a31,C[3][2]=a31+a32,C[3][3]=a33,C[3][4]=a31+a32+a33+a34,C[3][5]=a35,C[3][6]=a35+a36,...
这是A[][] 第三行 的一维树状数组
C[4][1]=a11+a21+a31+a41,C[4][2]=a11+a12+a21+a22+a31+a32+a41+a42,C[4][3]=a13+a23+a33+a43,...
这是A[][]数组 第一行+第二行+第三行+第四行 后的树状数组
注意加粗的部分,可以看出第二维之间储存值的关系和 第一维之间储存值得关系是一样的 ,
储存的项数都是 lowbit(i)。
所以修改和查询的函数,嵌套两个for循环就可以完成了
void modify(int a,int b,int val){ for(int i=a;i<=n;i+=lowbit(i)){ for(int j=b;j<=n;j+=lowbit(j)) s[i][j]+=val; } } int sum(int x,int y){ int ans=0; for(int i=x;i>0;i-=lowbit(i)){ for(int j=y;j>0;j-=lowbit(j)) ans+=s[i][j]; } return ans; }
以上数据来源: 树状数组讲的很好的文章
【源代码】
#include<iostream> #include<string> #include<cstring> #include<cstdio> using namespace std; const int maxn = 1111; int s[maxn][maxn]; int n; int lowbit(int x){ //求x二进制表示的最后一个1所在位置,,当然返回的值是最后一个1及其后面0所组成的二进制数 return x&(-x); } void modify(int a,int b,int val){ for(int i=a;i<=n;i+=lowbit(i)){ for(int j=b;j<=n;j+=lowbit(j)) s[i][j]+=val; } } int sum(int x,int y){ int ans=0; for(int i=x;i>0;i-=lowbit(i)){ for(int j=y;j>0;j-=lowbit(j)) ans+=s[i][j]; } return ans; } int getsum(int x1,int y1,int x2,int y2){ return sum(x2,y2)-sum(x1-1,y2)-sum(x2,y1-1)+sum(x1-1,y1-1); //先求最大区间 ,减去上面多余的,左边多余的, 加上左上角减去两次的。 } int main(){ int op; while(scanf("%d%d",&op,&n)!=EOF){ memset(s,0,sizeof(s)); int order; int a,b,c,d; while(scanf("%d",&order)!=EOF && order != 3){ if(order==1){ scanf("%d%d%d",&a,&b,&c); modify(a+1,b+1,c); } else { scanf("%d%d%d%d",&a,&b,&c,&d); int ans = getsum(a+1,b+1,c+1,d+1); printf("%d\n",ans); } } } return 0; }