题目:BZOJ3132.
题目大意:给定一个 n ∗ m n*m n∗m的矩阵初始全为 0 0 0,现在有 m m m个操作可能为:
1.给一个子矩阵加上一个数.
2.询问某个子矩阵的和.
1 ≤ n , m ≤ 2048 1\leq n,m\leq 2048 1≤n,m≤2048,询问数 q ≤ 2 ∗ 1 0 5 q\leq 2*10^5 q≤2∗105.
我们可以维护这个矩阵的差分数组 A i , j = a i , j − a i − 1 , j − a i , j − 1 + a i − 1 , j − 1 A_{i,j}=a_{i,j}-a_{i-1,j}-a_{i,j-1}+a_{i-1,j-1} Ai,j=ai,j−ai−1,j−ai,j−1+ai−1,j−1,那么矩阵加就变为四个单点加,但询问变复杂了.
我们考虑只需要求出 ( 1 , 1 ) (1,1) (1,1)到 ( x , y ) (x,y) (x,y)的子矩阵和,那么有:
∑ i = 1 x ∑ j = 1 y a i , j = ∑ i = 1 n ∑ j = 1 m ∑ k = 1 i ∑ t = 1 j A k , t = ∑ i = 1 n ∑ j = 1 m A k , t ( x − i + 1 ) ( y − j + 1 ) \sum_{i=1}^{x}\sum_{j=1}^{y}a_{i,j}=\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{k=1}^{i}\sum_{t=1}^{j}A_{k,t}=\sum_{i=1}^{n}\sum_{j=1}^{m}A_{k,t}(x-i+1)(y-j+1) i=1∑xj=1∑yai,j=i=1∑nj=1∑mk=1∑it=1∑jAk,t=i=1∑nj=1∑mAk,t(x−i+1)(y−j+1)
我们把括号内的系数展开:
( x − i + 1 ) ( y − j + 1 ) = x y − x ( j − 1 ) − y ( i − 1 ) + ( i − 1 ) ( j − 1 ) (x-i+1)(y-j+1)=xy-x(j-1)-y(i-1)+(i-1)(j-1) (x−i+1)(y−j+1)=xy−x(j−1)−y(i−1)+(i−1)(j−1)
我们只要用四个树状数组分别维护 A i , j , A i , j ( i − 1 ) , A i , j ( j − 1 ) , A i , j ( i − 1 ) ( j − 1 ) A_{i,j},A_{i,j}(i-1),A_{i,j}(j-1),A_{i,j}(i-1)(j-1) Ai,j,Ai,j(i−1),Ai,j(j−1),Ai,j(i−1)(j−1)即可.
时间复杂度 O ( q log n log m ) O(q\log n\log m) O(qlognlogm).
代码如下:
#include
using namespace std;
typedef long long LL;
const int N=2048;
char Rc(){
char c=getchar();
for (;c^'X'&&c^'L'&&c^'k'&&c!=EOF;c=getchar());
return c;
}
int Ri(){
int x=0,y=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar()) if (c=='-') y=-1;
for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
return x*y;
}
int n,m;
void into(){
Rc();n=Ri();m=Ri();
}
int c[4][N+9][N+9];
void Add(int id,int x,int y,int v){
for (int i=x;i<=n;i+=i&-i)
for (int j=y;j<=m;j+=j&-j) c[id][i][j]+=v;
}
void Add(int x,int y,int v){
Add(0,x,y,v);
Add(1,x,y,v*(x-1));
Add(2,x,y,v*(y-1));
Add(3,x,y,v*(x-1)*(y-1));
}
int Query(int id,int x,int y){
int res=0;
for (int i=x;i;i-=i&-i)
for (int j=y;j;j-=j&-j) res+=c[id][i][j];
return res;
}
int Query(int x,int y){
int res=0;
res+=x*y*Query(0,x,y);
res-=y*Query(1,x,y);
res-=x*Query(2,x,y);
res+=Query(3,x,y);
return res;
}
void getans(){
char opt;
for (;(opt=Rc())!=EOF;){
int x0,y0,x1,y1;
x0=Ri();y0=Ri();x1=Ri();y1=Ri();
if (opt=='L'){
int v=Ri();
Add(x0,y0,v);
Add(x0,y1+1,-v);
Add(x1+1,y0,-v);
Add(x1+1,y1+1,v);
}else{
int ans=0;
ans+=Query(x1,y1);
ans-=Query(x1,y0-1);
ans-=Query(x0-1,y1);
ans+=Query(x0-1,y0-1);
printf("%d\n",ans);
}
}
}
int main(){
into();
getans();
return 0;
}