前置知识:
一维树状数组的区间修改与区间查询。
简要题意:
维护二维数组的矩阵加与矩阵查。
很显然,如果你用 二维线段树 的话,常数较大,加上要开 ( ext{long long}),很可能会 ( ext{MLE + TLE}) 的双倍快乐。
所以我们要用 二维树状数组 解决这道题目。
考虑常规前缀和,二维的前缀和需要维护 (4) 个节点,我们也需要一一维护。
也就是我们要维护 (4) 个差分数组用来一一对应矩阵的四个角,并用 滚一维 的方式,把二维的更新。注意区间加和的细节。
时间复杂度:(mathcal{O}(n^2 log^2 n) - mathcal{O}(log^2 n)).
实际得分:(100pts).
双倍经验:P4514 上帝造题的七分钟,不过这道题目需要大力卡常(本人卡了半天还是 (81),自闭了,( ext{LOJ}) 评测器最快!)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(5000)
#pragma GCC optimize(1000000000)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
using namespace std;
const int N=(1<<12)+1;
#define int long long
inline int read(){char ch=getchar(); int f=1; while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
int x=0; while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f;}
inline void write(int x) {
if(x<0) {putchar('-');write(-x);return;}
if(x<10) {putchar(char(x%10+'0'));return;}
write(x/10);putchar(char(x%10+'0'));
}
int n,m;
struct BIT {
int a[N][N];
inline void add(int x,int y,int t) {
for(register int i=x;i<=n;i+=(i&-i))
for(register int j=y;j<=m;j+=(j&-j)) a[i][j]+=t;
} //加
inline int query(int x,int y) {
int t=0;
for(register int i=x;i>=1;i-=(i&-i))
for(register int j=y;j>=1;j-=(j&-j)) t+=a[i][j];
return t;
} //询问
}A,B,C,D; //四个树状数组
inline int calc(int x,int y) {
return A.query(x,y)*(x*y+x+y+1)-B.query(x,y)*(y+1)
-C.query(x,y)*(x+1)+D.query(x,y);
} //计算二维前缀和的答案
inline void Add(int x,int y,int t) {
A.add(x,y,t); B.add(x,y,t*x);
C.add(x,y,t*y); D.add(x,y,t*x*y);
} //修改四个节点
signed main() {
n=read(),m=read(); int op;
while(cin>>op) {
int x1=read(),y1=read(),x2,y2,t;
if(op==1) {
x2=read(),y2=read(); t=read(); Add(x1,y1,t); Add(x1,y2+1,-t);
Add(x2+1,y1,-t); Add(x2+1,y2+1,t);
} else x2=x1,y2=y1,write(calc(x2,y2)-calc(x1-1,y2)-calc(x2,y1-1)+calc(x1-1,y1-1)),
putchar('
');
}
return 0;
}