解题思路
二维树状数组。
对于修改操作单开一个矩阵,修改时利用差分思想,这样每个点
S[i][j]
S
[
i
]
[
j
]
的前缀和表示这个点修改了多少。
对于一个查询
(x,y)
(
x
,
y
)
,单独考虑从
(0,0)
(
0
,
0
)
到
(x,y)
(
x
,
y
)
的每一个点,一个点
(i,j)
(
i
,
j
)
会被算进从
(i,j)
(
i
,
j
)
到
(x,y)
(
x
,
y
)
所有点的前缀和里,所以
(i,j)
(
i
,
j
)
对本次查询的贡献为
S[i][j]×(x−i+1)×(y−j+1)
S
[
i
]
[
j
]
×
(
x
−
i
+
1
)
×
(
y
−
j
+
1
)
。
拆开变成:
S[i][j]×(x+1)×(y+1)−S[i][j]×j×(x+1)−S[i][j]×i×(y+1)+S[i][j]×i×j
S
[
i
]
[
j
]
×
(
x
+
1
)
×
(
y
+
1
)
−
S
[
i
]
[
j
]
×
j
×
(
x
+
1
)
−
S
[
i
]
[
j
]
×
i
×
(
y
+
1
)
+
S
[
i
]
[
j
]
×
i
×
j
,然后分别维护四个树状数组,查询时加到一起。
代码:
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
using namespace std;
int n,m;
struct ldx{
int a[2050][2050];
void add(int x,int y,int num){
for(int i=x;i<=n;i+=i&(-i))
for(int j=y;j<=m;j+=j&(-j))
a[i][j]+=num;
}
int ch(int x,int y){
int sum=0;
for(int i=x;i>0;i-=i&(-i))
for(int j=y;j>0;j-=j&(-j))
sum+=a[i][j];
return sum;
}
}T1,T2,T3,T4;
inline void tj(int x,int y,int num){
T1.add(x,y,num);
T2.add(x,y,num*x);
T3.add(x,y,num*y);
T4.add(x,y,num*x*y);
}
inline int solve(int x,int y){
return (x+1)*(y+1)*T1.ch(x,y)-(y+1)*T2.ch(x,y)-(x+1)*T3.ch(x,y)+T4.ch(x,y);
}
int main(){
int ai,bi,ci,di,ei;
char opt[5];
scanf("%s%d%d",opt,&n,&m);
while(~scanf("%s",opt)){
if(opt[0]=='L'){
scanf("%d%d%d%d%d",&ai,&bi,&ci,&di,&ei);
tj(ai,bi,ei);tj(ci+1,di+1,ei);
tj(ci+1,bi,-ei);tj(ai,di+1,-ei);
}
else {
scanf("%d%d%d%d",&ai,&bi,&ci,&di);
int ans=solve(ci,di)+solve(ai-1,bi-1)-solve(ci,bi-1)-solve(ai-1,di);
printf("%d",ans);
}
}
return 0;
}