3132: 上帝造题的七分钟
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 1004 Solved: 445
[Submit][Status][Discuss]
Description
“第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵。
第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作。
第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作。
第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围。
第五分钟,和雪说,要有耐心,于是便有了时间限制。
第六分钟,吃钢琴男说,要省点事,于是便有了保证运算过程中及最终结果均不超过32位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。”
——《上帝造裸题的七分钟》
所以这个神圣的任务就交给你了。
Input
输入数据的第一行为X n m,代表矩阵大小为n×m。
从输入数据的第二行开始到文件尾的每一行会出现以下两种操作:
L a b c d delta —— 代表将(a,b),(c,d)为顶点的矩形区域内的所有数字加上delta。
k a b c d —— 代表求(a,b),(c,d)为顶点的矩形区域内所有数字的和。
请注意,k为小写。
Output
针对每个k操作,在单独的一行输出答案。
Sample Input
X 4 4
L 1 1 3 3 2
L 2 2 4 4 1
k 2 2 3 3
Sample Output
12
HINT
对于100%的数据,1 ≤ n ≤ 2048, 1 ≤ m ≤ 2048, 1 ≤ abs(delta) ≤ 500,操作不超过200000个,保证运算过程中及最终结果均不超过32位带符号整数类型的表示范围。
题解
二维树状数组区间修改区间查询。。。
公式其实挺好推的,从一维扩展道二维就行。。。
反正就是维护下v[i][j]、v[i][j]*i、v[i][j]*j、v[i][j]*i*j 的前缀和
代码
//by 减维 #include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<cstdlib> #include<ctime> #include<cmath> #include<map> #include<bitset> #include<algorithm> #define ll long long using namespace std; int n,m; int lowbit(int x){return x&(-x);} struct tree{ int sum[2050][2050]; void change(int x,int y,int v) { for(int i=x;i<=n;i+=lowbit(i)) for(int j=y;j<=m;j+=lowbit(j)) sum[i][j]+=v; } int ask(int x,int y) { int ans=0; for(int i=x;i;i-=lowbit(i)) for(int j=y;j;j-=lowbit(j)) ans+=sum[i][j]; return ans; } }t1,t2,t3,t4; int calc(int x,int y) { return t1.ask(x,y)*(x+1)*(y+1)+t4.ask(x,y)-t2.ask(x,y)*(y+1)-t3.ask(x,y)*(x+1); } int main() { char op[5]; scanf("%s%d%d",op,&n,&m); int a,b,c,d,val; while(~scanf("%s",op)){ if(op[0]==‘L‘){ scanf("%d%d%d%d%d",&a,&b,&c,&d,&val); t1.change(a,b,val); t1.change(c+1,d+1,val); t1.change(a,d+1,-val); t1.change(c+1,b,-val); t2.change(a,b,val*a); t2.change(c+1,d+1,val*(c+1)); t2.change(a,d+1,-val*a); t2.change(c+1,b,-val*(c+1)); t3.change(a,b,val*b); t3.change(c+1,d+1,val*(d+1)); t3.change(a,d+1,-val*(d+1)); t3.change(c+1,b,-val*b); t4.change(a,b,val*a*b);t4.change(c+1,d+1,val*(c+1)*(d+1));t4.change(a,d+1,-val*a*(d+1));t4.change(c+1,b,-val*(c+1)*b); }else{ scanf("%d%d%d%d",&a,&b,&c,&d); printf("%d\n",calc(c,d)-calc(c,b-1)-calc(a-1,d)+calc(a-1,b-1)); } } return 0; }