题意:在一个大小为s*s的矩阵中,每一个单位格子上可能放着多部手机。手机数目可能增加或者减少。输入数据给一些手机增减的信息。然后对于每一个询问,给出询问范围内的手机数量。
思路:求二维数组内某一个矩阵的元素和。由于求和次数很多,如果用普通的数组方法时间复杂度O(n*n)会超时。应利用树状数组来解。
关于二维树状数组求区间和的公式推导 A(x,y)
如上图 A(x,y),B(x1,y1)。求图中蓝色面积。
我们知道二维树状数组的sum都是以从原点(这里原点是(1,1,))到改点的线段为对角线的矩形。因此求图中蓝色面积S,说白了,就是几个矩形面积减来减去减多了再加上,凑来凑去求面积。显然 s=s(x,y)-s(x,y1)-s(x1,y) + s(x1,y1) (就是大矩形-(橙色矩形+绿色矩形)*2+绿色矩形)。有了这个公式,便可计算蓝色区域面积了。因为矩形中存储的相当于是元素值,求得了面积,也即求得了sum。
AC代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define ll long long
using namespace std;
const int MAX=1<<28;
ll c[1500][1500],n;
int lowbit(int x)
{
return x&(-x);
}
void updata(int x,int y,int dt)
{
int i,j;
for(i=x; i<=n+1;i+=lowbit(i))
for(j=y; j<=n+1; j+=lowbit(j))
c[i][j]+=dt;
}
ll sum(int x,int y)
{
ll ans=0;
for(int i=x; i>0; i-=lowbit(i))
for(int j=y; j>0; j-=lowbit(j))
ans+=c[i][j];
return ans;
}
int main()
{
int ty,x,y,x1,y1,val;
memset(c,0,sizeof(c));
while(scanf("%d",&ty))
{
if(ty==3) break;
else if(ty==0) scanf("%d",&n);
else if(ty==1)
{
scanf("%d%d%d",&x,&y,&val);
updata(x+1,y+1,val);
}
else if(ty==2)
{
scanf("%d%d%d%d",&x1,&y1,&x,&y);
ll ans=0;
x++,y++;
ans=sum(x,y)-sum(x1,y)-sum(x,y1)+sum(x1,y1);
printf("%lld\n",ans);
}
}
return 0;
}
+