对于区间修改,我们在【例题4】区间修改区间查询中学会了一种区间查改方法,就是差分
根据差分我们可以推得
f
[
i
]
[
j
]
f[i][j]
f[i][j](矩形
i
i
i,
j
j
j的面积)
=
∑
i
n
∑
j
m
a
[
i
]
[
j
]
=
∑
i
n
∑
j
m
∑
k
i
∑
l
j
d
[
k
]
[
l
]
=\sum_i^n\sum_j^ma[i][j]=\sum_i^n\sum_j^m\sum_k^i\sum_l^jd[k][l]
=∑in∑jma[i][j]=∑in∑jm∑ki∑ljd[k][l]
通过类比以为可以化简得到
∑
i
n
∑
j
m
d
[
i
]
[
j
]
×
(
n
−
i
+
1
)
×
(
m
−
j
+
1
)
\sum_i^n\sum_j^md[i][j]\times(n-i+1)\times(m-j+1)
∑in∑jmd[i][j]×(n−i+1)×(m−j+1)
拆开可以得到:
∑
i
n
∑
j
m
(
n
+
1
)
×
(
m
+
1
)
×
d
[
i
]
[
j
]
−
(
n
+
1
)
×
j
×
d
[
i
]
[
j
]
−
(
m
+
1
)
×
i
×
d
[
i
]
[
j
]
+
i
×
j
×
d
[
i
]
[
j
]
\sum_i^n\sum_j^m(n+1)\times(m+1)\times d[i][j]-(n+1)\times j\times d[i][j]-(m+1)\times i\times d[i][j]+i\times j\times d[i][j]
∑in∑jm(n+1)×(m+1)×d[i][j]−(n+1)×j×d[i][j]−(m+1)×i×d[i][j]+i×j×d[i][j]
这里很显然我们只需要维护
d
[
i
]
[
j
]
d[i][j]
d[i][j] ,
j
×
d
[
i
]
[
j
]
j\times d[i][j]
j×d[i][j] ,
i
×
d
[
i
]
[
j
]
i\times d[i][j]
i×d[i][j] ,
i
×
j
×
d
[
i
]
[
j
]
i\times j\times d[i][j]
i×j×d[i][j]四个前缀和即可
注意:访问的时候注意容斥
Code
#include<bits/stdc++.h>
#define inl inline
#define int long long
#define ll long long
using namespace std;
const int N=2e3+50;
int read(){
int sum=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){sum=(sum<<3)+(sum<<1)+(c^48);c=getchar();}
return sum*f;
}
int lowbit(int x){return x&-x;}
int t[N][N],ti[N][N],tj[N][N],tij[N][N];
int n,m;
inl void add(int x,int y,int k){
for( int i=x;i<=n;i+=lowbit(i)){
for( int j=y;j<=m;j+=lowbit(j)){
t[i][j]+=k;
ti[i][j]+=x*k;
tj[i][j]+=y*k;
tij[i][j]+=x*y*k;
}
}
}
ll query(int x,int y){
int ans=0;
for( int i=x;i;i-=lowbit(i)){
for( int j=y;j;j-=lowbit(j)){
ans+=(x+1)*(y+1)*t[i][j]-ti[i][j]*(y+1)-tj[i][j]*(x+1)+tij[i][j];
}
}
return ans;
}
signed main(){
n=read(),m=read();
int opt;
while(scanf("%lld",&opt)!=EOF){
int x=read(),y=read(),x2=read(),y2=read();
if(opt==1){
int k=read();
add(x,y,k);add(x,y2+1,-k);add(x2+1,y,-k);add(x2+1,y2+1,k);
}
else{
printf("%lld\n",query(x2,y2)+query(x-1,y-1)-query(x2,y-1)-query(x-1,y2));
}
}
return 0;
}
写到这里鄙人的差分来搞树状数组区间问题也算是正式理解了 撒花花~~~~