二维线段树的模板题,和一维一样的思路,更新的时候注意一下细节。
存模板:
/*
二维线段树模板整理
*/
#include<cstdio>
#include<algorithm>
using namespace std;
#define lson (pos<<1)
#define rson (pos<<1|1)
const int maxn = 805;
const int INF = (1 << 30);
int n;
int posX[maxn],posY[maxn];//定位数组(快速找到更新区间,往上递推)
//Y方向线段树区间节点
struct Ny{
int l,r;
int minv,maxv;
};
//X方向线段树区间节点
struct Nx{
Ny nodey[maxn << 2];
int l,r;
void build(int l,int r,int pos){
nodey[pos].l = l;
nodey[pos].r = r;
nodey[pos].minv = INF;
nodey[pos].maxv = -INF;
if(l == r){
posY[l] = pos;
return;
}
int mid = (l + r) >> 1;
build(l,mid,lson);
build(mid + 1,r,rson);
}
int queryMax(int L,int R,int pos){ //L R为需要查询的区间
if(L <= nodey[pos].l && nodey[pos].r <= R)
return nodey[pos].maxv;
int mid = (nodey[pos].l + nodey[pos].r) >> 1;
int ret = - INF;
if(L <= mid)
ret = max(ret,queryMax(L,R,lson));
if(R > mid)
ret = max(ret,queryMax(L,R,rson));
return ret;
}
int queryMin(int L,int R,int pos){ //L R为需要查询的区间
if(L <= nodey[pos].l && nodey[pos].r <= R)
return nodey[pos].minv;
int mid = (nodey[pos].l + nodey[pos].r) >> 1;
int ret = INF;
if(L <= mid)
ret = min(ret,queryMin(L,R,lson));
if(R > mid)
ret = min(ret,queryMin(L,R,rson));
return ret;
}
}nodex[maxn << 2];
void build(int l,int r,int pos){
nodex[pos].l = l;
nodex[pos].r = r;
nodex[pos].build(1,n,1);
if(l == r){
posX[l] = pos;
return;
}
int mid = (l + r) >> 1;
build(l,mid,lson);
build(mid + 1,r,rson);
}
int queryMax(int x1,int x2,int y1,int y2,int pos){
if(x1 <= nodex[pos].l && nodex[pos].r <= x2){
return nodex[pos].queryMax(y1,y2,1);
}
int mid = (nodex[pos].l + nodex[pos].r) >> 1;
int ret = -INF;
if(x1 <= mid)
ret = max(ret,queryMax(x1,x2,y1,y2,lson));
if(x2 > mid)
ret = max(ret,queryMax(x1,x2,y1,y2,rson));
return ret;
}
int queryMin(int x1,int x2,int y1,int y2,int pos){
if(x1 <= nodex[pos].l && nodex[pos].r <= x2){
return nodex[pos].queryMin(y1,y2,1);
}
int mid = (nodex[pos].l + nodex[pos].r) >> 1;
int ret = INF;
if(x1 <= mid)
ret = min(ret,queryMin(x1,x2,y1,y2,lson));
if(x2 > mid)
ret = min(ret,queryMin(x1,x2,y1,y2,rson));
return ret;
}
/*
关于更新这里是个难点,根据定位的数组找到要更新的节点进行更新
更新的时候第一轮更行X坐标线段树,之后的几轮更新Y坐标线段树
*/
void update(int x,int y,int value){
int _x = posX[x],_y = posY[y];
//先更新横坐标
nodex[_x].nodey[_y].minv = nodex[_x].nodey[_y].maxv = value;
for(int i = _x; i >= 1; i >>= 1){
if(i != _x){
nodex[i].nodey[_y].minv =
min(nodex[i << 1].nodey[_y].minv,nodex[i << 1|1].nodey[_y].minv);
nodex[i].nodey[_y].maxv =
max(nodex[i << 1].nodey[_y].maxv,nodex[i << 1|1].nodey[_y].maxv);
}
}
//更新纵坐标线段树
for(int i = _x; i >= 1; i >>= 1){
for(int j = _y; j >= 1; j >>= 1){
if(j == _y) continue;
nodex[i].nodey[j].minv =
min(nodex[i].nodey[j << 1].minv,nodex[i].nodey[j << 1|1].minv);
nodex[i].nodey[j].maxv =
max(nodex[i].nodey[j << 1].maxv,nodex[i].nodey[j << 1|1].maxv);
}
}
}
int main(){
int T,Case = 1;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
build(1,n,1);
int value;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++){
scanf("%d",&value);
update(i,j,value);
}
int m,x,y,l;
scanf("%d",&m);
printf("Case #%d:\n",Case++);
while(m--){
scanf("%d%d%d",&x,&y,&l);
int x1 = x - l / 2; if(x1 < 1) x1 = 1;
int x2 = x + l / 2; if(x2 > n) x2 = n;
int y1 = y - l / 2; if(y1 < 1) y1 = 1;
int y2 = y + l / 2; if(y2 > n) y2 = n;
int maxv = queryMax(x1,x2,y1,y2,1);
int minv = queryMin(x1,x2,y1,y2,1);
int aver = (maxv + minv) / 2;
printf("%d\n",aver);
update(x,y,aver);
}
}
return 0;
}