二维线段树的模板题,和一维一样的思路,更新的时候注意一下细节。
存模板:
/* 二维线段树模板整理 */ #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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-10 14:01:55