HDU 4819 Mosaic(二维线段树)
给定一个矩阵,查询一块子矩阵的最大值和最小值,然后他们和的一半替换(x, y)这个位置,裸的二维线段树。
和一维差不多,只不过是一维当中保存的是最值,而这个保存的是个数组而已,而这个数组也是个一维的线段树,所以就是二维线段树。具体见代码注释。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1000; //每个x节点上有个纵向的y数组,就是一列 struct Nodey { int l, r; int Max, Min; }; int locx[maxn], locy[maxn];//对于给定的矩阵当中的位置(x, y)在线段树中对应的x和y的位置为locx[x], locy[y]; const int inf = 0x3f3f3f3f; int T, n;//n矩阵的大小 struct Nodex {//x节点,就是普通的一维的线段树 int l, r; Nodey sty[maxn<<2];//它的节点不是一个普通的值,而是一维的数组,其实就是一列 void build(int rt, int ll, int rr)//对于一列建树,和一维一样,注意区分ll和l,ll是列当中的区间左值,而l是行当中的区间左值 { sty[rt].l = ll; sty[rt].r = rr; sty[rt].Min = inf; sty[rt].Max = -inf; if (ll == rr) { locy[ll] = rt;//位置 return; } int mid = (ll + rr) / 2; build(rt << 1, ll, mid); build(rt << 1 | 1, mid + 1, rr); } int queryMin(int rt, int ll, int rr)//查询列当中ll-rr区间当中的最值 { if (sty[rt].l == ll && sty[rt].r == rr) return sty[rt].Min; int mid = (sty[rt].l + sty[rt].r) / 2; if (rr <= mid) return queryMin(rt << 1, ll, rr); else if (ll > mid) return queryMin(rt << 1 | 1, ll, rr); return min(queryMin(rt << 1, ll, mid), queryMin(rt << 1 | 1, mid + 1, rr)); } int queryMax(int rt, int ll, int rr) { if (sty[rt].l == ll && sty[rt].r == rr) return sty[rt].Max; int mid = (sty[rt].l + sty[rt].r) / 2; if (rr <= mid) return queryMax(rt << 1, ll, rr); else if (ll > mid) return queryMax(rt << 1 | 1, ll, rr); return max(queryMax(rt << 1, ll, mid), queryMax(rt << 1 | 1, mid + 1, rr)); } }stx[maxn<<2]; void build(int rt, int l, int r)//建树 { stx[rt].l = l; stx[rt].r = r; stx[rt].build(1, 1, n); if (l == r) { locx[l] = rt; return; } int mid = (l + r) / 2; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); } void modify(int x, int y, int val)//更改(x, y)这个点的值 { int tx = locx[x]; int ty = locy[y]; stx[tx].sty[ty].Min = stx[tx].sty[ty].Max = val; for (int i = tx; i; i >>= 1)//向上更新 PushUp for (int j = ty; j; j >>= 1) { if (i == tx && j == ty) continue; if (j == ty) { stx[i].sty[j].Min = min(stx[i<<1].sty[j].Min, stx[i<<1|1].sty[j].Min); stx[i].sty[j].Max = max(stx[i<<1].sty[j].Max, stx[i<<1|1].sty[j].Max); } else { stx[i].sty[j].Min = min(stx[i].sty[j<<1].Min, stx[i].sty[j<<1|1].Min); stx[i].sty[j].Max = max(stx[i].sty[j<<1].Max, stx[i].sty[j<<1|1].Max); } } } int queryMin(int rt, int x1, int x2, int y1, int y2)//查询在矩阵行为(x1 到 x2),列为(y1 到 y2)的最值 { if (stx[rt].l == x1 && stx[rt].r == x2) return stx[rt].queryMin(1, y1, y2); int mid = (stx[rt].l + stx[rt].r) / 2; if (x2 <= mid) return queryMin(rt << 1, x1, x2, y1, y2); else if (x1 > mid) return queryMin(rt << 1 | 1, x1, x2, y1, y2); return min(queryMin(rt << 1, x1, mid, y1, y2), queryMin(rt << 1 | 1, mid + 1, x2, y1, y2)); } int queryMax(int rt, int x1, int x2, int y1, int y2) { if (stx[rt].l == x1 && stx[rt].r == x2) return stx[rt].queryMax(1, y1, y2); int mid = (stx[rt].l + stx[rt].r) / 2; if (x2 <= mid) return queryMax(rt << 1, x1, x2, y1, y2); else if (x1 > mid) return queryMax(rt << 1 | 1, x1, x2, y1, y2); return max(queryMax(rt << 1, x1, mid, y1, y2), queryMax(rt << 1 | 1, mid + 1, x2, y1, y2)); } int main() { scanf("%d", &T); int kase = 0; while (T--) { scanf("%d", &n); build(1, 1, n);//建树 int mat; printf("Case #%d:\n", ++kase); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { scanf("%d", &mat); modify(i, j, mat);//更新 } int q; scanf("%d", &q); while (q--) { int x, y, len; scanf("%d %d %d", &x, &y, &len); len /= 2; int x1 = max(x - len, 1); int x2 = min(x + len, n); int y1 = max(y - len, 1); int y2 = min(y + len, n); int Max = queryMax(1, x1, x2, y1, y2); int Min = queryMin(1, x1, x2, y1, y2); int ans = (Min + Max) / 2; printf("%d\n", ans); modify(x, y, ans); } } return 0; }