题意:
在n*m的空间内执行2种操作 每次令一个矩形内所有元素增加v 或 查询一个矩形内的数字的和减去它四个角方向的矩形内数字的和 (操作2看下图 +的部分减去-的部分)
- - - -0000000- - - -
- - - -0000000- - - -
0000 ++++++0000
0000 ++++++0000
- - - -0000000- - - -
思路:
区间更新区间求和 第一感觉是线段树 但是n*m太大
考虑到求和操作的特点可以分两种方法做:(以上图举例)
1. 先加3 4行 再减1 2 3 4列 再减12 13 14 15 列
2. 先加3 4 行 再加5 6 7 8 9 10 11列 再减去全部
无论哪种做法都满足把列和行分开考虑 这样就可以用两个树状数组分别表示列和行来进行更新和求和
数组数组区间更新区间求和借鉴 WYL 大神讲解
http://hi.baidu.com/wyl8899/item/c3ac1c0eec3516ea34990267?qq-pf-to=pcqq.group
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define M 4000010
__int64 xd[M],xdi[M],yd[M],ydi[M];
int n,m,q;
__int64 all;
int lowbit(int x)
{
return x&(-x);
}
void add(__int64 *a,int x,__int64 v,int sz)
{
while(x<=sz)
{
a[x]+=v;
x+=lowbit(x);
}
}
__int64 sum(__int64 *a,int x)
{
__int64 res=0;
while(x)
{
res+=a[x];
x-=lowbit(x);
}
return res;
}
int main()
{
int x1,y1,x2,y2,op;
__int64 val,vv;
scanf("%d%d%d",&n,&m,&q);
while(q--)
{
scanf("%d",&op);
if(op)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%I64d\n",sum(xd,x2)*(x2+1)-sum(xd,x1-1)*x1-sum(xdi,x2)+sum(xdi,x1-1)+sum(yd,y2)*(y2+1)-sum(yd,y1-1)*y1-sum(ydi,y2)+sum(ydi,y1-1)-all);
}
else
{
scanf("%d%d%d%d%I64d",&x1,&y1,&x2,&y2,&val);
all+=val*(x2-x1+1)*(y2-y1+1);
vv=val*(y2-y1+1);
add(xd,x1,vv,n);
add(xd,x2+1,-vv,n);
add(xdi,x1,vv*x1,n);
add(xdi,x2+1,vv*(-x2-1),n);
vv=val*(x2-x1+1);
add(yd,y1,vv,m);
add(yd,y2+1,-vv,m);
add(ydi,y1,vv*y1,m);
add(ydi,y2+1,vv*(-y2-1),m);
}
}
return 0;
}