洛谷4514 上帝造题的七分钟(二维树状数组)
好久没写博客了.....
这段时间狂补一下
题目大意:
给定一个\(n*n\)的全0矩阵,每次有两种操作:
\(L\ a\ b\ c\ d\ delta\) 表示将左上角\((a,b)\),右下角\((c,d)\)的矩阵加\(delta\)
\(k\ a\ b \ c \ d\) 表示求左上角\((a,b)\),右下角\((c,d)\)的矩阵的和并输出
其中操作数\(\le 10^5\),\(n \le 2048\)
(此题卡空间,所以不要开\(long\ long\))
qwq既然是套路题,就直接说了
这个题考察的主要是二维树状数组
首先,类比一维,二维的树状数组\(c[i][j]\)表示,第\(i\)行 向上 \(lowbit(i)\)行,第\(j\)列,向左\(lowbit(j)\)列的和是多少。
那么修改也就显而易见了
struct BIT{
int c[maxn][maxn];
void modify(int x,int y,int p)
{
for (int i=x;i<=n;i+=lowbit(i))
for (int j=y;j<=m;j+=lowbit(j))
{
c[i][j]+=p;
}
}
int query(int x,int y)
{
int ans=0;
for (int i=x;i;i-=lowbit(i))
{
for (int j=y;j;j-=lowbit(j))
{
ans=ans+c[i][j];
}
}
return ans;
}
};
然后,我们来考虑怎么实现区间加呢?
一维的时候,我们运用的是差分的思想
那么我们对于二维,不妨使用\(d[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i][j]\)
那么我们对于修改一个\((x1,y1)->(x2,y2)\)的矩阵,我们只需要让\(d[x1][y1]+=delta,d[x1][y2+1]-=delta,d[x2+1][y1]-=delta,d[x2+1][y2+1]+=delta\)
就可以轻松完成了qwq
那....要是用差分数组,求和貌似就需要一点学问啊
对于求一个\((1,1)->(x,y)\)的矩阵的和
就是
\[ans = \sum_{i=1}^{x} \sum_{j=1}^{y}\sum_{h=1}^{i} \sum_{k=1}^{j} d[h][k]
\]
我们可以通过计算每个d的出现次数
来化简这个式子
\[ans = \sum_{i=1}^{x} \sum_{j=1}^{y} d[i][j]*(x-i+1)*(y-j+1)
\]
然后最终的式子就是
\[\sum_{i=1}^{x} \sum_{j=1}^{y} d[i][j]*(xy+x+y+1) - d[i][j]*i*(y+1)-d[i][j]*j*(x+1)+d[i][j]*i*j
\]
那么我们只需要维护四个树状数组,就OK了
直接上代码
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2051;
int lowbit(int x)
{
return (x & (-x));
}
int n,m;
struct BIT{
int c[maxn][maxn];
void modify(int x,int y,int p)
{
for (int i=x;i<=n;i+=lowbit(i))
for (int j=y;j<=m;j+=lowbit(j))
{
c[i][j]+=p;
}
}
int query(int x,int y)
{
int ans=0;
for (int i=x;i;i-=lowbit(i))
{
for (int j=y;j;j-=lowbit(j))
{
ans=ans+c[i][j];
}
}
return ans;
}
};
BIT ymh,ymhi,ymhj,ymhij;
char s[10];
int x1,x2,yy,y2;
void add(int x,int y,int p)
{
ymh.modify(x,y,p);
ymhi.modify(x,y,p*x);
ymhj.modify(x,y,p*y);
ymhij.modify(x,y,p*x*y);
}
int sum(int x,int y)
{
return ymh.query(x,y)*(x*y+x+y+1)-ymhi.query(x,y)*(y+1)-ymhj.query(x,y)*(x+1)+ymhij.query(x,y);
}
signed main()
{
scanf("%s",s+1);
n=read(),m=read();
while (scanf("%s",s+1)!=EOF)
{
int p;
if (s[1]=='L')
{
x1=read(),yy=read(),x2=read(),y2=read();
p=read();
add(x1,yy,p);
add(x1,y2+1,-p);
add(x2+1,yy,-p);
add(x2+1,y2+1,p);
}
else
{
x1=read(),yy=read(),x2=read(),y2=read();
printf("%d\n",sum(x2,y2)-sum(x2,yy-1)-sum(x1-1,y2)+sum(x1-1,yy-1));
}
}
return 0;
}