思路:
令数组f[i][j]代表从矩阵[i,j]-[n,m]的增量,那么我们每次修改(对矩阵[a,b]-[c,d]增加x)时就只需要执行以下4个操作:
f[a][b]+=w,f[a][d+1]-=w,f[c+1][d]-=w,f[c+1][d+1]+=w。
那么,很明显,对于一个位置[x,y],全部增量就是sigma(i=1->x,j=1->y,f[i][j]),(对于一个位置[x,y],全部增量为s[x][y])
那么,对于一个矩阵[1,1]-[x,y](可以理解为二维的前缀和)的总增量为s[1][1]+s[1][2]+…+s[x][y],
用归纳法可以发现,矩阵中某一位置i,j的增量f[i,j]在上式中出现次数为(x+1-i)(y+1-j)=(x+1)(y+1)-i(y+1)-j(x+1)+ij,
所以s[1][1]+s[1][2]+…+s[x][y]
=sigma(x+1-i)(y+1-j)f[i][j]
=sigma((x+1)(y+1)f[i][j]-i(y+1)f[i][j]-j(x+1)f[i][j]+ijf[i][j])
=(x+1)(y+1)sigmaf[i][j]-(y+1)sigma(if[i][j])-(x+1)sigma(jf[i][j])+sigma(ijf[i][j])
所以,我们可以用4个二维树状数组来维护f[i][j],if[i][j],jf[i][j],ijf[i][j]的前缀和即可。
代码(26行)(请原谅我无耻的压行~):
#include<cstdio>
#include<cstring>
#define MAXN 2050
#define clear(x) memset(x,0,sizeof(x))
#define lowbit(x)(((~(x))+1)&x)
#define For(i,x)for(int i=x;i<=n;i+=lowbit(i))
#define FOR(i,x)for(int i=x;i;i-=lowbit(i))
int T[MAXN][MAXN],A[MAXN][MAXN],B[MAXN][MAXN],C[MAXN][MAXN],n,m;
void Add(int x,int y,int z)
{For(i,x)For(j,y)T[i][j]+=z,A[i][j]+=z*x,B[i][j]+=z*y,C[i][j]+=z*x*y;}
int S(int x,int y){
int Q=0,W=0,E=0,R=0;
FOR(i,x)FOR(j,y)Q+=T[i][j],W+=A[i][j],E+=B[i][j],R+=C[i][j];
return Q*(x+1)*(y+1)-W*(y+1)-E*(x+1)+R;
}
int main(){
int a,b,c,d,X;
char s[1];
scanf("%s%d%d",&s,&n,&m);
clear(T),clear(A),clear(B),clear(C);
while(scanf("%s",&s)!=EOF){
if(s[0]=='k') scanf("%d%d%d%d",&a,&b,&c,&d),printf("%d\n",S(c,d)-S(a-1,d)-S(c,b-1)+S(a-1,b-1));
else scanf("%d%d%d%d%d",&a,&b,&c,&d,&X),Add(a,b,X),Add(a,d+1,-X),Add(c+1,b,-X),Add(c+1,d+1,X);
}
return 0;
}