HDU4819之二维线段树

  • Post author:
  • Post category:其他


题目传送门:

http://vjudge.net/contest/131028#problem/G

题意:

给定一个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);  
        }  
    }  
}



版权声明:本文为superxtong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。