码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-08-09 18:51:52      阅读:118      评论:0      收藏:0      [点我收藏+]

标签:

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

存模板:

/*
    二维线段树模板整理
*/
#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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

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

标签:

原文地址:http://blog.csdn.net/u013451221/article/details/47378135

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!