【HDU 4819】Mosaic 二维线段树模板

二维线段树的模板题,和一维一样的思路,更新的时候注意一下细节。

存模板:

/*
    二维线段树模板整理
*/
#include<cstdio>
#include<algorithm>
using namespace std;
#define lson (pos<<1)
#define rson (pos<<1|1)
const int maxn = 805;
const int  INF = (1 << 30);
int n;
int posX[maxn],posY[maxn];//定位数组(快速找到更新区间,往上递推)
//Y方向线段树区间节点
struct Ny{
    int l,r;
    int minv,maxv;
};
//X方向线段树区间节点
struct Nx{
    Ny nodey[maxn << 2];
    int l,r;
    void build(int l,int r,int pos){
        nodey[pos].l = l;
        nodey[pos].r = r;
        nodey[pos].minv = INF;
        nodey[pos].maxv = -INF;
        if(l == r){
            posY[l] = pos;
            return;
        }
        int mid = (l + r) >> 1;
        build(l,mid,lson);
        build(mid + 1,r,rson);
    }
    int queryMax(int L,int R,int pos){  //L R为需要查询的区间
        if(L <= nodey[pos].l && nodey[pos].r <= R)
            return nodey[pos].maxv;
        int mid = (nodey[pos].l + nodey[pos].r) >> 1;
        int ret = - INF;
        if(L <= mid)
            ret = max(ret,queryMax(L,R,lson));
        if(R  > mid)
            ret = max(ret,queryMax(L,R,rson));
        return ret;
    }
    int queryMin(int L,int R,int pos){  //L R为需要查询的区间
        if(L <= nodey[pos].l && nodey[pos].r <= R)
            return nodey[pos].minv;
        int mid = (nodey[pos].l + nodey[pos].r) >> 1;
        int ret = INF;
        if(L <= mid)
            ret = min(ret,queryMin(L,R,lson));
        if(R  > mid)
            ret = min(ret,queryMin(L,R,rson));
        return ret;
    }
}nodex[maxn << 2];
void build(int l,int r,int pos){
    nodex[pos].l = l;
    nodex[pos].r = r;
    nodex[pos].build(1,n,1);
    if(l == r){
        posX[l] = pos;
        return;
    }
    int mid = (l + r) >> 1;
    build(l,mid,lson);
    build(mid + 1,r,rson);
}
int queryMax(int x1,int x2,int y1,int y2,int pos){
    if(x1 <= nodex[pos].l && nodex[pos].r <= x2){
        return nodex[pos].queryMax(y1,y2,1);
    }
    int mid = (nodex[pos].l + nodex[pos].r) >> 1;
    int ret = -INF;
    if(x1 <= mid)
        ret = max(ret,queryMax(x1,x2,y1,y2,lson));
    if(x2  > mid)
        ret = max(ret,queryMax(x1,x2,y1,y2,rson));
    return ret;
}
int queryMin(int x1,int x2,int y1,int y2,int pos){
    if(x1 <= nodex[pos].l && nodex[pos].r <= x2){
        return nodex[pos].queryMin(y1,y2,1);
    }
    int mid = (nodex[pos].l + nodex[pos].r) >> 1;
    int ret = INF;
    if(x1 <= mid)
        ret = min(ret,queryMin(x1,x2,y1,y2,lson));
    if(x2  > mid)
        ret = min(ret,queryMin(x1,x2,y1,y2,rson));
    return ret;
}
/*
    关于更新这里是个难点,根据定位的数组找到要更新的节点进行更新
    更新的时候第一轮更行X坐标线段树,之后的几轮更新Y坐标线段树
*/
void update(int x,int y,int value){
    int _x = posX[x],_y = posY[y];
    //先更新横坐标
    nodex[_x].nodey[_y].minv = nodex[_x].nodey[_y].maxv = value;
    for(int i = _x; i >= 1; i >>= 1){
        if(i != _x){
            nodex[i].nodey[_y].minv =
            min(nodex[i << 1].nodey[_y].minv,nodex[i << 1|1].nodey[_y].minv);
            nodex[i].nodey[_y].maxv =
            max(nodex[i << 1].nodey[_y].maxv,nodex[i << 1|1].nodey[_y].maxv);
        }
    }
    //更新纵坐标线段树
    for(int i = _x; i >= 1; i >>= 1){
        for(int j = _y; j >= 1; j >>= 1){
            if(j == _y) continue;
            nodex[i].nodey[j].minv =
            min(nodex[i].nodey[j << 1].minv,nodex[i].nodey[j << 1|1].minv);
            nodex[i].nodey[j].maxv =
            max(nodex[i].nodey[j << 1].maxv,nodex[i].nodey[j << 1|1].maxv);
        }
    }
}
int main(){
    int T,Case = 1;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        build(1,n,1);
        int value;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++){
                scanf("%d",&value);
                update(i,j,value);
            }
        int m,x,y,l;
        scanf("%d",&m);
        printf("Case #%d:\n",Case++);
        while(m--){
            scanf("%d%d%d",&x,&y,&l);
            int x1 = x - l / 2; if(x1 < 1) x1 = 1;
            int x2 = x + l / 2; if(x2 > n) x2 = n;
            int y1 = y - l / 2; if(y1 < 1) y1 = 1;
            int y2 = y + l / 2; if(y2 > n) y2 = n;
            int maxv = queryMax(x1,x2,y1,y2,1);
            int minv = queryMin(x1,x2,y1,y2,1);
            int aver = (maxv + minv) / 2;
            printf("%d\n",aver);
            update(x,y,aver);
        }
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值