题目链接:点击打开链接
题意:给你一个n*n的矩阵, 每个点是一个数字, Q个操作,每次选择一个子矩阵, 把中心元素替换成子矩阵中最大值和最小值之和的二分之一。
思路: 经典的二维线段树模型, 二维线段树也是树套树的一种, 就是一棵树的每个结点上再维护一棵树, 需要注意的是, 对于第一棵树, 每个结点值PushUp的时候, 因为要更新的是一棵树, 所以不能简单的像线段树一样更新, 而是应该调用更新第二颗树。 相应的, 结点值的更新也略有不同:
二维线段树其实就是行线段树套列线段树, 那么行线段树就要用行下标更新行, 用列下标更新列。 (鸟神告诉我的)
细节参见代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; typedef long double ld; const ld eps = 1e-9, PI = 3.1415926535897932384626433832795; const int mod = 1000000000 + 7; const int INF = 0x3f3f3f3f; // & 0x7FFFFFFF const int seed = 131; const ll INF64 = ll(1e18); const int maxn = 800 + 10; int T,xl,x,q,L,isleap, y, xr, yl, yr,n,maxv[maxn<<2][maxn<<2],minv[maxn<<2][maxn<<2],rt; struct node { int minv, maxv; node(int minv=0, int maxv=0):minv(minv),maxv(maxv) {} }; void PushUp(int o) { maxv[rt][o] = max(maxv[rt][o<<1], maxv[rt][o<<1|1]); minv[rt][o] = min(minv[rt][o<<1], minv[rt][o<<1|1]); } void buildy(int l, int r, int o) { int m = (l + r) >> 1; if(l == r) { if(isleap) { scanf("%d",&minv[rt][o]); maxv[rt][o] = minv[rt][o]; } else { maxv[rt][o] = max(maxv[rt<<1][o], maxv[rt<<1|1][o]); minv[rt][o] = min(minv[rt<<1][o], minv[rt<<1|1][o]); } return ; } buildy(l, m, o<<1); buildy(m+1, r, o<<1|1); PushUp(o); } void buildx(int l, int r, int o) { int m = (l + r) >> 1; if(l == r) { rt = o; isleap = 1; buildy(1, n, 1); return ; } buildx(l, m, o<<1); buildx(m+1, r, o<<1|1); rt = o; isleap = 0; buildy(1, n, 1); } void updatey(int L, int R, int x, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { if(isleap) maxv[rt][o] = minv[rt][o] = x; else { maxv[rt][o] = max(maxv[rt<<1][o], maxv[rt<<1|1][o]); minv[rt][o] = min(minv[rt<<1][o], minv[rt<<1|1][o]); } return ; } if(L <= m) updatey(L, R, x, l, m, o<<1); if(m < R) updatey(L, R, x, m+1, r, o<<1|1); PushUp(o); } void updatex(int L, int R, int x, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { rt = o; isleap = 1; updatey(yl, yr, x, 1, n, 1); return ; } if(L <= m) updatex(L, R, x, l, m, o<<1); if(m < R) updatex(L, R, x, m+1, r, o<<1|1); rt = o; isleap = 0; updatey(yl, yr, x, 1, n, 1); } node queryy(int L, int R, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { return node(minv[rt][o], maxv[rt][o]); } node ans = node(INF, -INF); if(L <= m && m >= R) return queryy(L, R, l, m, o<<1); else if(L > m && m < R) return queryy(L, R, m+1, r, o<<1|1); else { ans = queryy(L, R, l, m, o<<1); node cur = queryy(L, R, m+1, r, o<<1|1); ans.minv = min(ans.minv, cur.minv); ans.maxv = max(ans.maxv, cur.maxv); return ans; } } node queryx(int L, int R, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { rt = o; return queryy(yl, yr, 1, n, 1); } node ans = node(INF, -INF); if(L <= m && m >= R) return queryx(L, R, l, m, o<<1); else if(L > m && m < R) return queryx(L, R, m+1, r, o<<1|1); else { ans = queryx(L, R, l, m, o<<1); node cur = queryx(L, R, m+1, r, o<<1|1); ans.minv = min(ans.minv, cur.minv); ans.maxv = max(ans.maxv, cur.maxv); return ans; } } int main() { scanf("%d",&T); for(int i=1;i<=T;i++) { printf("Case #%d:\n",i); scanf("%d",&n); buildx(1, n, 1); scanf("%d",&q); yl = 1; yr = n; node hehe = queryx(1, n, 1, n, 1); while(q--) { scanf("%d%d%d",&x,&y,&L); --L; L /= 2; yl = max(1, y - L); yr = min(n, y + L); xl = max(1, x - L); xr = min(n, x + L); node cur = queryx(xl, xr, 1, n, 1); int now = (cur.minv + cur.maxv) / 2; printf("%d\n",now); yl = yr = y; updatex(x, x, now, 1, n, 1); } } return 0; }