您的位置:首页 > 其它

POJ 1195 Mobile phones(二维树状数组,点修改,区间查询)

2015-08-25 11:14 567 查看
题目链接: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: