时空限制 1000ms / 131MB
题目描述
裸体就意味着身体。
“第一分钟,X说,要有矩阵,于是便有了一个里面写满了00的n×mn×m矩阵。
第二分钟,L说,要能修改,于是便有了将左上角为(a,b)(a,b),右下角为(c,d)(c,d)的一个矩形区域内的全部数字加上一个值的操作。
第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作。
第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围。
第五分钟,和雪说,要有耐心,于是便有了时间限制。
第六分钟,吃钢琴男说,要省点事,于是便有了保证运算过程中及最终结果均不超过32位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。”
——《上帝造裸题的七分钟》
所以这个神圣的任务就交给你了。
输入格式:
输入数据的第一行为X n m,代表矩阵大小为n×mn×m。
从输入数据的第二行开始到文件尾的每一行会出现以下两种操作:
L a b c d delta —— 代表将(a,b),(c,d)(a,b),(c,d)为顶点的矩形区域内的所有数字加上delta。
k a b c d —— 代表求(a,b),(c,d)(a,b),(c,d)为顶点的矩形区域内所有数字的和。
请注意,k为小写。
输出格式:
针对每个k操作,在单独的一行输出答案。
说明
对于10%的数据,
1≤n≤16,1≤m≤161≤n≤16,1≤m≤16
1
≤
n
≤
16
,
1
≤
m
≤
161
≤
n
≤
16
,
1
≤
m
≤
16
, 操作不超过200个.
对于60%的数据,
1≤n≤512,1≤m≤5121≤n≤512,1≤m≤512
1
≤
n
≤
512
,
1
≤
m
≤
5121
≤
n
≤
512
,
1
≤
m
≤
512
.
对于100%的数据,
1≤n≤2048,1≤m≤2048,−500≤delta≤500
1
≤
n
≤
2048
,
1
≤
m
≤
2048
,
−
500
≤
d
e
l
t
a
≤
500
操作不超过200000个,保证运算过程中及最终结果均不超过32位带符号整数类型的表示范围。
题目分析
题目空间卡掉了二维线段树
那么只能考虑二维树状数组了
树状数组对 二维的区间加区间求和 的处理方式
可以从树状数组的区间加 单点求和 逐步拓展出来
接下来以
a[i]
a
[
i
]
表示原数列,
sum[i]
s
u
m
[
i
]
表示
a[i]
a
[
i
]
的前缀和
b[i]
b
[
i
]
表示引入的增量数组
对于区间加 单点和
若操作指令为 区间
[ll,rr]
[
l
l
,
r
r
]
都加v
那么我们令
b[ll]+=v,b[rr+1]−=v
b
[
l
l
]
+
=
v
,
b
[
r
r
+
1
]
−
=
v
当我们查询
a[x]
a
[
x
]
的值时
a[x]
a
[
x
]
的增量为
∑xi=1b[i]
∑
i
=
1
x
b
[
i
]
(即b[x]的前缀和)
这里
b[x]
b
[
x
]
的前缀和显然可以用树状数组维护
这么做的正确性也很显然
对于
1<=x<ll
1
<=
x
<
l
l
,修改后
b[x]
b
[
x
]
前缀和不变
对于
ll<=x<=rr
l
l
<=
x
<=
r
r
,修改后
b[x]
b
[
x
]
前缀和增加了v
对于
rr<x<=N
r
r
<
x
<=
N
,修改后
b[x]
b
[
x
]
前缀和不变(ll处与rr+1处抵消)
现在在上面基础上扩展树状数组的 区间加 区间和
a[x]
a
[
x
]
的前缀
sum[x]
s
u
m
[
x
]
的增量为
由此我们 开两个增量数组
令 b0[ll]+=v, b0[rr+1]−=v b 0 [ l l ] + = v , b 0 [ r r + 1 ] − = v
b1[ll]+=ll∗v, b1[rr+1]−=(rr+1)∗v b 1 [ l l ] + = l l ∗ v , b 1 [ r r + 1 ] − = ( r r + 1 ) ∗ v
那么区间
[ll,rr]
[
l
l
,
r
r
]
的和为
ans=(sum[rr]+(rr+1)∗qsum(b0,rr)−qsum(b1,rr))−(sum[ll−1]+ll∗qsum(b0,ll−1)−qsum(b1,ll−1))
a
n
s
=
(
s
u
m
[
r
r
]
+
(
r
r
+
1
)
∗
q
s
u
m
(
b
0
,
r
r
)
−
q
s
u
m
(
b
1
,
r
r
)
)
−
(
s
u
m
[
l
l
−
1
]
+
l
l
∗
q
s
u
m
(
b
0
,
l
l
−
1
)
−
q
s
u
m
(
b
1
,
l
l
−
1
)
)
按照上面的方法再次扩展出树状数组的 二维 区间加 区间和
矩阵 a[i][j] a [ i ] [ j ] 的二维前缀和 sum[i][j] s u m [ i ] [ j ] 的增量为
展开得
那么更新与查询与上述类似
增量数组需要开四个
分别维护
b[i][j],j∗b[i][j],i∗b[i][j],ij∗b[i][j]
b
[
i
]
[
j
]
,
j
∗
b
[
i
]
[
j
]
,
i
∗
b
[
i
]
[
j
]
,
i
j
∗
b
[
i
]
[
j
]
在本题中由于矩阵没有初始值
所以只需计算增量数组即可
若有初始值只需增加原矩阵的二维前缀和
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
#define lowbit(x) ((x)&(-x))
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
const int maxn=2110;
int n,m;
int b[maxn][maxn][4];
char ss[3];
void add(int d,int x,int y,int v)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=m;j+=lowbit(j))
b[i][j][d]+=v;
}
int qsum(int d,int x,int y)
{
int res=0;
for(int i=x;i>0;i-=lowbit(i))
for(int j=y;j>0;j-=lowbit(j))
res+=b[i][j][d];
return res;
}
void update(int x,int y,int v)
{
add(0,x,y,v);
add(1,x,y,y*v);
add(2,x,y,x*v);
add(3,x,y,x*y*v);
}
int query(int x,int y)
{
int tt1=(x*y+x+y+1)*qsum(0,x,y);
int tt2=(x+1)*qsum(1,x,y);
int tt3=(y+1)*qsum(2,x,y);
int tt4=qsum(3,x,y);
return tt1-tt2-tt3+tt4;
}
int main()
{
scanf("%s",&ss);
n=read();m=read();
while(scanf("%s",&ss)!=EOF)
{
int a=read(),b=read(),c=read(),d=read();
if(ss[0]=='L')
{
int x=read();
update(a,b,x); update(c+1,d+1,x);
update(a,d+1,-x); update(c+1,b,-x);
//以下为每个点更新的具体内容
//add(0,a,b,x); add(1,a,b,b*x); add(2,a,b,a*x); add(3,a,b,a*b*x);
//add(0,a,d+1,-x); add(1,a,d+1,-(d+1)*x); add(2,a,d+1,-a*x); add(3,a,d+1,-a*(d+1)*x);
//add(0,c+1,b,-x); add(1,c+1,b,-b*x); add(2,c+1,b,-(c+1)*x); add(3,c+1,b,-(c+1)*b*x);
//add(0,c+1,d+1,x); add(1,c+1,d+1,(d+1)*x); add(2,c+1,d+1,(c+1)*x); add(3,c+1,d+1,(c+1)*(d+1)*x);
}
else if(ss[0]=='k')
printf("%d\n",query(c,d)-query(a-1,d)-query(c,b-1)+query(a-1,b-1));
//查询的具体内容
//query(c,d)=(c*d+c+d+1)*qsum(0,c,d)-(c+1)*qsum(1,c,d)-(d+1)*qsum(2,c,d)+qsum(3,c,d);
//query(a-1,d)=((a-1)*d+(a-1)+d+1)*qsum(0,a-1,d)-(a-1+1)*qsum(1,a-1,d)-(d+1)*qsum(2,a-1,d)+qsum(3,a-1,d);
//query(c,b-1)=(c*(b-1)+c+(b-1)+1)*qsum(0,c,b-1)-(c+1)*qsum(1,c,b-1)-(b-1+1)*qsum(2,c,b-1)+qsum(3,c,b-1);
//query(a-1,b-1)=((a-1)*(b-1)+(a-1)+(b-1)+1)*qsum(0,a-1,b-1)-(a-1+1)*qsum(1,a-1,b-1)-(b-1+1)*qsum(2,a-1,b-1)+qsum(3,a-1,b-1);
}
return 0;
}