题面
【题目描述】
假设
T
a
m
p
e
r
e
Tampere
Tampere区域的第四代手机基地站运行如下。该区域被划分为一些正方形(方阵)。这些正方形构成一个
S
S
S╳
S
S
S的矩阵,矩阵行和列的编号从
0
0
0到
S
−
1
S-1
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 L \leq X \leq R,B \leq Y \leq T L≤X≤R,B≤Y≤T |
3 | 结束程序 | 该标志数仅仅给出一次并将是最后一个标志数。 |
所有数值将始终在范围内,因而不需要检查。特别是,当
A
A
A为负时,可以假定它不会把正方形内的数目减到
0
0
0以下。范围的序号从
0
0
0开始。例如,对于一个
4
4
4*
4
4
4的表,
X
X
X和
Y
Y
Y的变化范围为
0
≤
X
≤
3
,
0
≤
Y
≤
3
0\leq X\leq 3, 0\leq Y\leq 3
0≤X≤3,0≤Y≤3。
对于一个标志数非(不是)
2
2
2的行,你的程序不应回答任何内容。如果标志数是
2
2
2,你的程序应当将答案以一个整数的形式写到标准输出来回答查询。
【输出】
对于每一个标志数为
2
2
2的,输出结果。
【样例输入】
0 4
1 1 2 3
2 0 0 2 2
3
【样例输出】
3
【数据范围】
矩阵表大小 | S S S✖ S S S | 1 ✖ 1 ≤ S ✖ S ≤ 1024 ✖ 1024 1✖1 \leq S✖S \leq 1024✖1024 1✖1≤S✖S≤1024✖1024 |
---|---|---|
任意时间的单元值 | V V V | 0 ≤ V ≤ 2 15 – 1 0 \leq V \leq 2^{15} –1 0≤V≤215–1 ( = 32767 =32767 =32767) |
更新量 | A A A | − 2 15 ≤ A ≤ 2 15 – 1 -2^{15} \leq A \leq 2^{15}–1 −215≤A≤215–1 ( = 32767 = 32767 =32767) |
输入中标志数的数目 | U U U | 3 ≤ U ≤ 60002 3 \leq U \leq 60002 3≤U≤60002 |
整个矩阵表中手机数的最大值 | M M M | M = 2 30 M= 2^{30 } M=230 |
在 20 20 20个输入中, 16 16 16个输入(矩阵表)的大小最多是 512 ✖ 512 512✖512 512✖512。
算法分析
二维树状数组模板题目
本题对矩阵进行操作,对矩阵进行询问,方法与一维树状数组类似,才有二维树状数组。
参考程序
#include<bits/stdc++.h>
using namespace std;
int n;
long long c[N][N];
long long ans;
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int y,long long k) //区间更新
{
int i=x;
while(i<=N)
{
int j=y;
while(j<=N)
{
c[i][j]+=k;
j+=lowbit(j);
}
i+=lowbit(i);
}
}
long long sum(int x,int y) //区间求和,矩阵(1,1)~(x,y)的和
{
long long ans=0;
int i=x;
while(i>0)
{
int j=y;
while(j>0)
{
ans+=c[i][j];
j-=lowbit(j);
}
i-=lowbit(i);
}
return ans;
}
int main()
{
int x,y,x1,y1,m;
long long k;
while(1)
{
scanf("%d",&m);
if(m==0) {scanf("%d",&x);memset(c,0,sizeof(c));}
if(m==1)
{
scanf("%d%d%lld",&x,&y,&k);
update(x+1,y+1,k);
}
if(m==2)
{
scanf("%d%d%d%d",&x,&y,&x1,&y1);
x++;y++;x1++;y1++;
ans=sum(x1,y1)-sum(x-1,y1)-sum(x1,y-1)+sum(x-1,y-1); //二维前缀和
printf("%lld\n",ans);
}
if(m==3) break;
}
return 0;
}