【模板篇】树状数组(六)
上次我们聊到了二维树状数组的 单点加 区间查.
那么我们yy一下区间加 单点查也不难.
我们就让树状数组维护差分数组, 只不过是变成了二维差分, 都差不多的.
我们可以仿照一维的 改写成这样
int c[N][N],n,m;
void add(int x,int y,int s){
for(int i=x;i<=n;i+=i&-i)
for(int j=y;j<=m;j+=j&-j)
c[i][j]+=s;
}
int query(int x,int y,int s=0){
for(int i=x;i;i-=i&-i)
for(int j=y;j;j-=i&-j)
s+=c[i][j];
}
void Add(int x1,int y1,int x2,int y2,int s){
add(x1,y1,s); add(x1,y2+1,-s); add(x2+1,y1,-s); add(x2+1,y2+1,s);
}
而其实二维树状数组也可以做到区间加, 区间查的.
而且据说线段树套线段树是没法维护的....
我们看一道本板子题: 上帝造题的七分钟
那怎么做呢? 我们还是仿照一维的推柿子.
不过今天我按照之前的方法推柿子感觉并不好推, 于是获取了一种新的推法.
由于我们维护的差分数组的前缀和才是单点的值, 也就是说我们计算\(a_i\)时, \(c_1\sim c_i\)每个值都会被计算一次.
这样我们计算\(\sum_{i=1}^na_i\)的时候,\(c_1\)应该会出现\(n\)次, \(c_2\)应该会出现\(n-1\)次, ... , \(c_k\)会出现\(n-k+1\)次, ... ,\(c_n\)会出现一次. 所以
这样我们用两个树状数组分别维护\(c_i\)的和和\(c_i*i\)的和即可.
而之前我们得出的结论也不是错的, 如果我们这么拆
就变成了维护\(c_I\)和\(c_i*(i-1)\), 最后结果应该是一样的, 具体用哪种看个人喜好吧... (似乎前面那种用起来比较舒服..)
情况扩展到了二维, 除了二维差分复杂了一(hen)些(duo)以外, 原理上是一样的.
我们依然用\(c_{i,j}\)维护差分数组, 所以显然\(\sum_{i=1}^n\sum_{j=1}^mc_{i,j}=a_{n,m}\)
然后仿照一维的, 把一个查询拆成四个, 对于每个查询,
这里面很显然每个\(c_i,j\)被使用的次数等于以\((i,j)\)为左上角,\((n,m)\)为右下角的矩形面积(不信你可以画个图试试), 也就是\((n-i+1)*(m-j+1)\), 所以
所以按照套路我们只需要开四个树状数组分别维护\(c_{i,j},c_{i,j}*i,c_{i,j}*j,c_{i,j}*i*j\)就行了..
不管是区间加还是区间查都巨繁琐qwq...
下面给出代码;
#include <cstdio>
inline int gn(int a=0,char c=0,int f=1){
for(;(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-') c=getchar(),f=-1;
for(;c>47&&c<58;c=getchar()) a=a*10+c-48;
return a*f;}
struct BIT{
int c[2050][2050],n,m;
void add(int x,int y,int s){
for(int i=x;i<=n;i+=i&-i)
for(int j=y;j<=m;j+=j&-j)
c[i][j]+=s;
}
int query(int x,int y,int s=0){
for(int i=x;i;i-=i&-i)
for(int j=y;j;j-=j&-j)
s+=c[i][j];
return s;
}
}a,b,c,d;
void Add(int x,int y,int s){
a.add(x,y,s); b.add(x,y,s*x); c.add(x,y,s*y); d.add(x,y,s*x*y);
}
int Query(int x,int y){
return a.query(x,y)*(x+1)*(y+1)-b.query(x,y)*(y+1)-c.query(x,y)*(x+1)+d.query(x,y);
}
int main(){
int n=gn(),m=gn(); char opt[4];
a.n=b.n=c.n=d.n=n; a.m=b.m=c.m=d.m=m;
while(~scanf("%s",opt)){
if(opt[0]=='L'){
int x1=gn(),y1=gn(),x2=gn(),y2=gn(),s=gn();
Add(x1,y1,s); Add(x1,y2+1,-s); Add(x2+1,y1,-s); Add(x2+1,y2+1,s);
}
else{
int x1=gn(),y1=gn(),x2=gn(),y2=gn();
printf("%d\n",Query(x2,y2)-Query(x1-1,y2)-Query(x2,y1-1)+Query(x1-1,y1-1));
}
}
}