做 LG1527,发现自己竟然还不会二维树状数组,赶紧恶补一下。
下面的内容是随手写的,原理不是很难
单点改,区间查
void update(int x,int y,int v){
for(int i=x;i<=n;i+=lowbit(i)){
for(int j=y;j<=m;j+=lowbit(j))
c[i][j]+=v;
}
}
int getsum(int x,int y,int v=0){
for(int i=x;i;i-=lowbit(i)){
for(int j=y;j;j-=lowbit(j))
v+=c[i][j];
}
return v;
}
最后答案统计
\[\sum_{i=a}^{c}\sum_{i=b}^{d}a_{i,j}=s_{c,d}-s_{c-1,d}-s_{c,d-1}+s_{c-1,d-1} \]区间改,单点查
定义差分数组 \(d_{i,j}\),每次修改操作 \(d_{a,b}\leftarrow +v,d_{c+1,b}\leftarrow-v,d_{a,d+1}\leftarrow-v,d_{c+1,d+1}\leftarrow+v\)
\[a_{x,y}=\sum_{i=1}^{x}\sum_{j=1}^{y}d_{i,j} \]转化为单点改,区间查
区间改,区间查询
\[\begin{align} s_{x,y}&=\sum_{i=1}^{x}\sum_{j=1}^{y}a_{i,j}\\ &=\sum_{i=1}^{x}\sum_{j=1}^{y}\sum_{k=1}^{i}\sum_{l=1}^{j}d_{k,l}\\ &=\sum_{i=1}^{x}\sum_{j=1}^{y}d_{i,j}\times(x-i+1)(y-j+1)\\ &=(x+1)(y+1)\sum_{i=1}^{x}\sum_{j=1}^y d_{i,j}-(x+1)\sum_{i=1}^{x}\sum_{j=1}^{y}d_{i,j}\times j-(y+1)\sum_{i=1}^{x}\sum_{j=1}^{y}d_{i,j}\times i+\sum_{i=1}^{x}\sum_{j=1}^{y}d_{i,j}\times ij \end{align} \]额外维护 \(d_{i,j}\times j,d_{i,j}\times i,d_{i,j}\times ij\) 的二维前缀和即可
LG4514 上帝造题的七分钟
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>ttfa;
const int N=2050;
inline int lowbit(int x){return x&-x;}
int n,m;
struct BIT_2di{
int c[N][N];
void update(int x,int y,int v){
for(int i=x;i<=n;i+=lowbit(i)){
for(int j=y;j<=m;j+=lowbit(j))
c[i][j]+=v;
}
}
int getsum(int x,int y,int v=0){
for(int i=x;i;i-=lowbit(i)){
for(int j=y;j;j-=lowbit(j))
v+=c[i][j];
}
return v;
}
}s,si,sj,sij;
void sij_update(int x,int y,int v){
s.update(x,y,v);
si.update(x,y,v*x);
sj.update(x,y,v*y);
sij.update(x,y,v*x*y);
}
int sij_getsum(int x,int y,int v=0){
v+=(x+1)*(y+1)*s.getsum(x,y);
v-=(x+1)*sj.getsum(x,y);
v-=(y+1)*si.getsum(x,y);
v+=sij.getsum(x,y);
return v;
}
int main(){
char opt[3];
scanf("%s%d%d",opt,&n,&m);
while(scanf("%s",opt)!=EOF){
int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d);
if(opt[0]=='L'){
int v;scanf("%d",&v);
sij_update(a,b,v);
sij_update(c+1,b,-v);
sij_update(a,d+1,-v);
sij_update(c+1,d+1,v);
}else{
int v=0;
v+=sij_getsum(c,d);
v-=sij_getsum(a-1,d);
v-=sij_getsum(c,b-1);
v+=sij_getsum(a-1,b-1);
printf("%d\n",v);
}
}
return 0;
}
标签:单点,树状,int,sum,leftarrow,times,二维,小记
From: https://www.cnblogs.com/BigSmall-En/p/18605845