1. 程式人生 > >HDU4819之二維線段樹

HDU4819之二維線段樹

題意:
給定一個n*n的矩陣,每次給定一個子矩陣區域(x,y,l),求出該區域內的最大值(A)和最小值(B),輸出(A+B)/2,並用這個值更新矩陣[x,y]的值。

樹套樹的做法,外層線段樹的一個節點由內層線段樹構成,內層線段樹和普通線段樹一樣。

見程式碼:

//http://vjudge.net/contest/131028#problem/G
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define maxn 801
#define inf 0x3f3f3f3f int maxi[maxn*3][maxn*3]; int mini[maxn*3][maxn*3]; int a[maxn][maxn]; int n; int val; //修改的值 int x, y; //修改點,設為全域性變數就不用傳到引數裡 int x1, x2, y1, y2; //查詢的區間 int crx; //只表示一行的外層線段樹節點編號 int cmax, cmin; //記錄查詢區間的最大值最小值 void buildy(int rx, int ry, int l, int r) { if(l == r){ if(rx == crx){ //
外層線段樹只表示一行,l==r,則這個為點,直接賦值 maxi[rx][ry] = mini[rx][ry] = a[x][l]; } else{ //外層線段樹是一段,則為一列的值,所以由rx(外層)的左子樹和右子樹更新(也就是同一列的上下區域) int lrx = rx<<1, rrx = rx<<1|1; maxi[rx][ry] = max(maxi[lrx][ry], maxi[rrx][ry]); mini[rx][ry] = min(mini[lrx][ry], mini[rrx][ry]); } return
; } int m =(l+r)>>1; int lc = ry<<1, rc = ry<<1|1; buildy(rx, lc, l, m); buildy(rx, rc, m+1,r); maxi[rx][ry] = max(maxi[rx][lc], maxi[rx][rc]); mini[rx][ry] = min(mini[rx][lc], mini[rx][rc]); } void buildx(int rx, int l, int r) { int m = (l+r)>>1; if(r > l){ buildx(rx<<1, l, m); buildx(rx<<1|1, m+1,r); } if(l == r) {crx = rx; x = l;} buildy(rx, 1, 1, n); } void updatey(int rx, int ry, int l, int r) { if(l == r){ if(rx == crx) maxi[rx][ry] = mini[rx][ry] = val; else{ int lrx = rx<<1, rrx = rx<<1|1; maxi[rx][ry] = max(maxi[lrx][ry], maxi[rrx][ry]); mini[rx][ry] = min(mini[lrx][ry], mini[rrx][ry]); } return; } int m = (l+r)>>1; int lc = ry<<1, rc =ry<<1|1; if(y <= m) updatey(rx, lc, l, m); else updatey(rx, rc, m+1, r); maxi[rx][ry] = max(maxi[rx][lc], maxi[rx][rc]); mini[rx][ry] = min(mini[rx][lc], mini[rx][rc]); } void updatex(int rx, int l, int r) { int m = (l+r)>>1; int lc = rx<<1, rc =rx<<1|1; if(r > l){ if(x <= m) updatex(lc, l ,m); else updatex(rc, m+1, r); } if(l == r) crx = rx; updatey(rx, 1, 1, n); } void qy(int rx, int ry, int l, int r) { if(y1 <= l && y2 >= r){ cmin = min(cmin, mini[rx][ry]); cmax = max(cmax, maxi[rx][ry]); return; } int m = (l+r)>>1; int lc = ry<<1, rc =ry<<1|1; if(y1 <= m) qy(rx, lc, l, m); if(y2 > m) qy(rx, rc, m+1, r); } void qx(int rx, int l, int r) { if(x1 <= l && x2 >= r){ qy(rx, 1, 1, n); return; } int m = (l+r)>>1; int lc = rx<<1, rc =rx<<1|1; if(x1 <= m) qx(lc, l, m); if(x2 > m) qx(rc, m+1, r); } int main() { int t, cnt = 1; scanf("%d", &t); while(t--){ memset(maxi, -inf, sizeof(maxi)); memset(mini, inf, sizeof(mini)); printf("Case #%d:\n", cnt++); scanf("%d", &n); buildx(1, 1, n); for(int i = 1; i<=n; i++) for(int j=1; j<=n; j++) scanf("%d", &a[i][j]); buildx(1, 1, n); int l; int q; scanf("%d",&q); while(q--){ scanf("%d%d%d", &x, &y, &l); l>>=1; x1 = max(1, x-l); x2 = min(n, x+l); y1 = max(1, y-l); y2 = min(n, y+l); cmax = -inf, cmin = inf; qx(1, 1, n); val = (cmin+cmax)>>1; printf("%d\n", val); crx=-1; updatex(1, 1, n); } } }