洛谷 P4514 上帝造题的七分钟 解题报告
P4514 上帝造题的七分钟
题目背景
裸体(裸题)就意味着身体(神题)。
题目描述
“第一分钟,X说,要有矩阵,于是便有了一个里面写满了\(0\)的\(n \times m\)矩阵。
第二分钟,L说,要能修改,于是便有了将左上角为\((a,b)\),右下角为\((c,d)\)的一个矩形区域内的全部数字加上一个值的操作。
第三分钟,k说,要能查询,于是便有了求给定矩形区域内的全部数字和的操作。
第四分钟,彩虹喵说,要基于二叉树的数据结构,于是便有了数据范围。
第五分钟,和雪说,要有耐心,于是便有了时间限制。
第六分钟,吃钢琴男说,要省点事,于是便有了保证运算过程中及最终结果均不超过32位有符号整数类型的表示范围的限制。
第七分钟,这道题终于造完了,然而,造题的神牛们再也不想写这道题的程序了。”
——《上帝造裸题的七分钟》
所以这个神圣的任务就交给你了。
输入输出格式
输入格式:
输入数据的第一行为\(X\) \(n\) \(m\),代表矩阵大小为\(n \times m\)。
从输入数据的第二行开始到文件尾的每一行会出现以下两种操作:
L a b c d delta
—— 代表将\((a,b),(c,d)\)为顶点的矩形区域内的所有数字加上\(delta\)。
k a b c d
—— 代表求\((a,b),(c,d)\)为顶点的矩形区域内所有数字的和。
请注意,\(k\)为小写。
输出格式:
针对每个k操作,在单独的一行输出答案。
说明
对于\(10\%\)的数据,\(1 ≤ n ≤ 16, 1 ≤ m ≤ 16\), 操作不超过200个.
对于\(60\%\)的数据,\(1 ≤ n ≤ 512, 1 ≤ m ≤ 512\).
对于\(100\%\)的数据,\(1 ≤ n ≤ 2048, 1 ≤ m ≤ 2048, -500 ≤ delta ≤ 500\),操作不超过200000个,保证运算过程中及最终结果均不超过32位带符号整数类型的表示范围。
by XLk
说起来上午推了倒是退出来了,但是没搞清楚把什么放在外面乘结果错了有点怀疑人生看了题解发现自己还搞麻烦了(我太蒻了
很显然是胡乱对差分数组搞事的题目
设差分数组\(d_{i,j}\)
则有\(a_{x,y}=\sum_{i=1}^{x} \sum_{j=1}^y d_{i,j}\)
对于前缀和再求一次
\(f_{i,j}=\sum_{i=1}^{x} \sum_{j=1}^{y} \sum_{k=1}^{i} \sum_{l=1}^{y} d_{i,j}\)
\(=\sum_{i=1}^{x} \sum_{j=1}^{y} (x+1-i) \times (y+1-j) d_{i,j}\)
\(=(x+1) \times (y+1) \sum_{i=1}^{x} \sum_{j=1}^{y} d_{i,j} -(y+1) \sum_{i=1}^{x} \sum_{j=1}^{y} i \times d_{i,j} -(x+1) \sum_{i=1}^{x} \sum_{j=1}^{y} j \times d_{i,j} +\sum_{i=1}^{x} \sum_{j=1}^{y} i \times j \times d_{i,j}\)
二维维护四个什么和就行了
(我上午傻乎乎的把所有的\(x\),\(y\)啊全甩进去了。。
Code:
#include <cstdio>
const int N=2500;
int s[4][N][N],n,m;
int query(int typ,int x,int y)
{
int ans=0;
for(int i=x;i;i-=i&-i)
for(int j=y;j;j-=j&-j)
ans+=s[typ][i][j];
return ans;
}
void change(int typ,int x,int y,int delta)
{
for(int i=x;i<=n;i+=i&-i)
for(int j=y;j<=m;j+=j&-j)
s[typ][i][j]+=delta;
}
void modify(int x,int y,int delta)
{
change(0,x,y,delta);
change(1,x,y,y*delta);
change(2,x,y,x*delta);
change(3,x,y,x*y*delta);
}
int ask(int x,int y)
{
int ans=0;
ans+=(x+1)*(y+1)*query(0,x,y);
ans-=(x+1)*query(1,x,y);
ans-=(y+1)*query(2,x,y);
ans+=query(3,x,y);
return ans;
}
int main()
{
char op[4];int a,b,c,d,de;
scanf("%s%d%d",op,&n,&m);
while(scanf("%s%d%d%d%d",op,&a,&b,&c,&d)!=EOF)
{
if(op[0]=='L')
{
scanf("%d",&de);
modify(a,b,de);
modify(a,d+1,-de);
modify(c+1,b,-de);
modify(c+1,d+1,de);
}
else
{
int ans=0;
ans+=ask(c,d);
ans-=ask(a-1,d);
ans-=ask(c,b-1);
ans+=ask(a-1,b-1);
printf("%d\n",ans);
}
}
return 0;
}
2018.9.4