题目链接
题意:
给定一个N*N的矩阵,每个格子都有一个数,再给出Q个询问,每次询问以(x,y)为中心的边长为L(L必为奇数)的正方形矩阵中的最大值和最小值,并修改(x,y)的值为(MAX+MIN)/2。
树套树。以x建线段树,每个x区间中又有一个全区间的y线段树。
里面还是有一些细节的:
1、全局变量的利用。
2、buildy和updatey函数中有个变量k,分别用作 记录x的位置,判断当前区间是否在判读区间内。总体是用作标记。
3、单独修改,区间查询,所以没有pushdown函数。如果有区间修改,就得适合的加pushdown函数,看情况吧。
4、复杂度O(log ^ 2)。
5、还有一种 四叉树 的做法,题解链接。不推荐用。
部分代码:
#define ls i<<1
#define rs i<<1|1
#define mid ((l+r)>>1)
#define lson ls,l,mid
#define rson rs,mid+1,r
const int maxn=800+7;
int T,n,Q,a[maxn][maxn],xl,xr,yl,yr,t,p,q;
int mx[maxn<<2][maxn<<2],mi[maxn<<2][maxn<<2];
void pushupx(int i,int j){
mx[i][j]=max(mx[ls][j],mx[rs][j]);
mi[i][j]=min(mi[ls][j],mi[rs][j]);
}
void pushupy(int i,int j){
mx[i][j]=max(mx[i][j<<1],mx[i][j<<1|1]);
mi[i][j]=min(mi[i][j<<1],mi[i][j<<1|1]);
}
void buildy(int x,int i,int l,int r,int k){
if(l==r){
if(k) mx[x][i]=mi[x][i]=a[k][r];
else pushupx(x,i);
return;
}
buildy(x,lson,k); buildy(x,rson,k);
pushupy(x,i);
}
void buildx(int i,int l,int r){
if(l==r){
buildy(i,1,1,n,r);
return;
}
buildx(lson); buildx(rson);
buildy(i,1,1,n,0);
}
void updatey(int x,int i,int l,int r,int k){
if(l>yr||r<yl) return;
if(yl<=l&&r<=yr){
if(k) mx[x][i]=mi[x][i]=t;
else pushupx(x,i);
return;
}
updatey(x,lson,k); updatey(x,rson,k);
pushupy(x,i);
}
void updatex(int i,int l,int r){
if(l>xr||r<xl) return;
if(xl<=l&&r<=xr){
updatey(i,1,1,n,r);
return;
}
updatex(lson); updatex(rson);
updatey(i,1,1,n,0);
}
void queryy(int x,int i,int l,int r){
if(l>yr||r<yl) return;
if(yl<=l&&r<=yr){
p=max(p,mx[x][i]);
q=min(q,mi[x][i]);
return;
}
queryy(x,lson); queryy(x,rson);
}
void queryx(int i,int l,int r){
if(l>xr||r<xl) return;
if(xl<=l&&r<=xr){
queryy(i,1,1,n);
return;
}
queryx(lson); queryx(rson);
}
int main(){
T=read();
for(int v=1;v<=T;v++){
n=read(); int x,y,l;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=read();
buildx(1,1,n);
Q=read(); printf("Case #%d:\n",v);
while(Q--){
x=read(); y=read(); l=read();
l>>=1; p=0; q=1e9+7;
xl=max(1,x-l); yl=max(1,y-l);
xr=min(n,x+l); yr=min(n,y+l);
queryx(1,1,n); t=(p+q)>>1;
xl=xr=x; yl=yr=y;
updatex(1,1,n);
printf("%d\n",t);
}
}
}
另一种写法
关于这种单点修改、区间查询、二维线段树的题,还有一种写法模板:hdu 4819 Mosaic
他的这种写法也可以借鉴,虽然不是我的代码风格,但也要有注意的。
1、树套树,一般可以写在结构体中。(之后我有篇博客会整理。)这种结构体中的函数套另一个结构体的函数,很方便。
2、他的Modify函数,用的是线段树中的 非递归实现 ,可以说他用线段树很熟练了,其它也可以转换为非递归实现,因为这题只是单点修改。区间修改的话,非递归实现比较难写。
3、如果他这种可以用全局变量来记录查询区间的最大/小值,这代码还可以更短。