题目链接如下:
很有意思的一个二维线段树。
一开始我想,这么简单,把二维拉到一维不就行了吗,结果就是发现,在求那个长方形的区间和的时候无从下手。
然后用二维写。
一个二维数组来维护和,每个行代表的是一个线段树,每一列也构成线段树,而数组的位置代表的是行是[l1,r1],列是[l2,r2]的长方形的和。
那么update的时候:
我们先用二分限定x区间到输入的x的位置,再用二分限定y的位置,进行单个点上的更新就好了。这里我们要注意的是其他的节点的总和的更新,我们在单个线段树的时候一般是要pushup,这里也差不多,我们要对[l1,r1],[l2,r2]的每一个长方形进行更新。
query的修改也如出一辙。
具体代码如下所示:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<queue>
#include<string>
#include<cmath>
#include<climits>
using namespace std;
const int MAXN=1050;
int n,val,X1,Y1,X2,Y2,tmp_x,tmp_y;
int sum[MAXN*3][MAXN*3];
void update_y(int x,int l,int r,int rtx,int rty){
if (l==r){
if (x!=-1){
sum[rtx][rty]+=val;
} else{
sum[rtx][rty]=sum[rtx<<1][rty]+sum[rtx<<1|1][rty];
}
return;
}
int mid=(l+r)>>1;
if (tmp_y<=mid){
update_y(x,l,mid,rtx,rty<<1);
} else{
update_y(x,mid+1,r,rtx,rty<<1|1);
}
sum[rtx][rty]=sum[rtx][rty<<1]+sum[rtx][rty<<1|1];
}
void update_x(int l,int r,int rtx){
if (l==r){
update_y(l,1,n,rtx,1);
return;
}
int mid=(l+r)>>1;
if (tmp_x<=mid){
update_x(l,mid,rtx<<1);
} else{
update_x(mid+1,r,rtx<<1|1);
}
update_y(-1,1,n,rtx,1);
}
long long query_y(int l,int r,int rtx,int rty){
if (Y1<=l && Y2>=r){
return sum[rtx][rty];
}
long long ans=0;
int mid=(l+r)>>1;
if (Y1<=mid){
ans+= query_y(l,mid,rtx,rty<<1);
}
if (Y2>mid){
ans+= query_y(mid+1,r,rtx,rty<<1|1);
}
return ans;
}
long long query_x(int l,int r,int rtx){
if (X1<=l && X2>=r){
return query_y(1,n,rtx,1);
}
long long ans=0;
int mid=(l+r)>>1;
if (X1<=mid){
ans+=query_x(l,mid,rtx<<1);
}
if (X2>mid){
ans+=query_x(mid+1,r,rtx<<1|1);
}
return ans;
}
int main(){
int instr;
while (scanf("%d %d",&instr,&n)!=EOF){
memset(sum,0, sizeof(sum));
while (scanf("%d",&instr)){
if (instr==3) break;
else if (instr==1){
scanf("%d %d %d",&tmp_x,&tmp_y,&val);
tmp_x++,tmp_y++;
update_x(1,n,1);
}else{
scanf("%d %d %d %d",&X1,&Y1,&X2,&Y2);
X1++,X2++,Y1++,Y2++;
printf("%lld\n", query_x(1,n,1));
}
}
}
return 0;
}