例题
「IOI2001」Mobile Phones
题目描述
假设Tampere区域的第四代手机基地站运行如下。该区域被划分为一些正方形(方阵)。这些正方形构成一个S╳S的矩阵,矩阵行和列的编号从0到S-1。每个正方形包含一个基地站。由于一个手机可能从一个正方形移动到另一个正方形,或者手机可能开机或关机,所以,在一个正方形内正在使用的手机数目是随时变化的。有时,每个基地站需要将正在使用的手机数的变化用矩阵的行和列报告给主基地站。
请你写一个程序,接收这些报告并回答有关任一个长方形区域内当前正在使用的手机总数的查询。
输入
输入是从标准输入读入整数,对查询的回答是把一个整数写到标准输出。输入格式如下。每个输入占用一行,每行由一个标志数和一些参数构成,标志数和这些参数的格式见下表。
标志数
参 数
意 义
0
S
用全零来初始化矩阵,大小为 S´S. 该标志数仅仅给出一次,并将是第一个标志数。
1
X Y A
将A的值加到矩阵表方阵(X,Y)当前正在使用的手机数目中。A 可正可负。
2
L B R T
在方阵(X,Y)中查询当前正在使用的手机数的总和,其中L <= X <= R,B <= Y <= T
3
结束程序. 该标志数仅仅给出一次并将是最后一个标志数。
所有数值将始终在范围内,因而不需要检查。特别是,当A为负时,可以假定它不会把正方形内的数目减到0以下。范围的序号从0开始。例如,对于一个4*4的表,X和Y的变化范围为0≤X≤3, 0≤Y≤3。
对于一个标志数非(不是)2的行,你的程序不应回答任何内容。如果标志数是2,你的程序应当将答案以一个整数的形式写到标准输出来回答查询。
输出
样例输入
0 4
1 1 2 3
2 0 0 2 2
3
样例输出
3
分析
这是一个求区间和的题目,但是区间会变化,所以使用二维树状数组。
代码
#include<bits/stdc++.h>
using namespace std;
#define N 1024+5
#define INF 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define full(a,b) memset(a,b,sizeof a)
int n;
long long tree[N][N];
void update(int x,int y,int z){//把[x,y]+z
for(int i=x;i<=N;i+=lowbit(i))
for(int j=y;j<=N;j+=lowbit(j))
tree[i][j]+=1LL*z;
}
long long sum(int x,int y){//求[1~x][1~y]的和
long long ret=0;
for(int i=x;i>0;i-=lowbit(i))
for(int j=y;j>0;j-=lowbit(j))
ret+=1LL*tree[i][j];
return ret;
}
int main(){
int x;
scanf("%d%d",&x,&n);
while(1){
int m;scanf("%d",&m);
if(m==3)return 0;
if(m==1){
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
x+=2,y+=2;
update(x,y,k);
}
else {
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1+=2,y1+=2;x2+=2,y2+=2;
printf("%lld\n",sum(x2,y2)-sum(x1-1,y2)-sum(x2,y1-1)+sum(x1-1,y1-1));//二维前缀和
}
}
}