看了董晓老师的博客,但是没找到洛谷题,实在不想读英文(不是,写点理解巩固一下这方面的知识;
前置知识:具有线段树的基础,并有一定理解(能一定程度上的运用),感觉就能较为轻松的看懂
Mobile phones-poj 1195http://poj.org/problem?id=1195题意要求:
给一个矩阵,初始化为全0。有以下操作:
(1)将 (x,y) 元素加 a(点修)
(2)求矩阵 [(x1,y1),(x2,y2)] 所有元素的和(区查)
考虑使用线段树,但是发现这里是二维空间,相对的,我们考虑维护一个二维线段树,一维维护行(外层),一维维护列(内层)。
图片来源于董晓的博客,思路很清晰,稍微自己再理解理解就好
(主要是由图解就很会助于自己的理解)传送门https://www.cnblogs.com/dx123/p/17903781.html
如何维护某个点:外层经过的点均入内,内层经过的点均修改
如何区查:外层覆盖即入内,内层覆盖均返回
这里在经过的每一个位置都要入内,可以这么理解:先不要管列,只看x1,x2(只看行),把它当作一个区间,然后看作一个线段树进行维护,这样一来,因为有范围更大的区间都包含这个点,且又维护的区间和,所以就以维护区间和的方式,从大到小都要更新,只不过是别的地方是pushup,这里直接从上往下的时候就更新好了。列也是这个道理,固定完某几行后,不看行,只看列即可,这样就可以理解树套树的大概含义了。(或许可以看成没有懒标记的变种,点修改)
代码如下(摘):
#include
#include
#include
using namespace std;
#define N 1050
#define uls u<<1
#define urs u<<1|1
#define vls v<<1
#define vrs v<<1|1
#define mid ((l+r)>>1)
int n,sum[N<<2][N<<2]; //节点区间和
void changeY(int u,int v,int l,int r,int y,int a){ //内修
sum[u][v]+=a; //内层经过的节点均修改,先修改
if(l==r) return;
if(y<=mid) changeY(u,vls,l,mid,y,a);
else changeY(u,vrs,mid+1,r,y,a);
}
void changeX(int u,int l,int r,int x,int y,int a){ //外修
changeY(u,1,1,n,y,a); //外层经过的节点均入内
if(l==r) return;
if(x<=mid) changeX(uls,l,mid,x,y,a);
else changeX(urs,mid+1,r,x,y,a);
}
int queryY(int u,int v,int l,int r,int y1,int y2){ //内查
if(y1<=l&&r<=y2) return sum[u][v]; //内层覆盖即返回
if(y2<=mid) return queryY(u,vls,l,mid,y1,y2);
else if(y1>mid) return queryY(u,vrs,mid+1,r,y1,y2);
else return queryY(u,vls,l,mid,y1,mid)
+queryY(u,vrs,mid+1,r,mid+1,y2);
//这里是董晓老师的方法,当然如果常规设一个ans然后求和也是一样的
}
int queryX(int u,int l,int r,int x1,int x2,int y1,int y2){ //外查
if(x1<=l&&r<=x2) return queryY(u,1,1,n,y1,y2); //外层覆盖即入内
if(x2<=mid) return queryX(uls,l,mid,x1,x2,y1,y2);
else if(x1>mid) return queryX(urs,mid+1,r,x1,x2,y1,y2);
else return queryX(uls,l,mid,x1,mid,y1,y2)
+queryX(urs,mid+1,r,mid+1,x2,y1,y2);
}
int main(){
int op,x,y,a,x1,x2,y1,y2;
while(~scanf("%d",&op)){
if(op==0) scanf("%d",&n),
memset(sum,0,sizeof(sum));//初始化
if(op==1) scanf("%d%d%d",&x,&y,&a),
changeX(1,1,n,x+1,y+1,a);
if(op==2) scanf("%d%d%d%d",&x1,&y1,&x2,&y2),
printf("%d\n",queryX(1,1,n,x1+1,x2+1,y1+1,y2+1));
if(op==3) break;//3就结束
}
return 0;
}