HDU 4819 Mosaic(二维线段树)

题目链接:点击打开链接

题意:给你一个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;
}


你可能感兴趣的:(HDU,二维线段树)