【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;
}

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

时间: 2024-10-10 14:01:55

【HDU 4819】Mosaic 二维线段树模板的相关文章

HDU 4819 Mosaic --二维线段树(树套树)

题意: 给一个矩阵,每次查询一个子矩阵内的最大最小值,然后更新子矩阵中心点为(Max+Min)/2. 解法: 由于是矩阵,且要求区间最大最小和更新单点,很容易想到二维的线段树,可是因为之前没写过二维的线段树,所以没跳出来.后来熟悉了一下,原来很多细节地方都没有考虑到. 这里build,update,query都分为两个函数,第一个为Y轴的(sub_update),第二个为X轴的(update),不仅每个sub_update或sub_build后面要加Y轴的pushup函数,而且每个update或

hdu 4819 二维线段树模板

/* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 1010; int N, Q; struct Nodey { int l, r; int Max, Min; }; int locx[MAXN], l

树套树+【UVALive】6709 Mosaic 二维线段树

题目链接:6709 Mosaic 题解:参考这个博客:二维线段树,先按行建树然后每一个节点也是一个棵线段树按列建. #include<bits/stdc++.h> #include<cmath> #include<set> #include<cstdio> #include<iomanip> #include<iostream> #include<string> #include<cstring> #inclu

UVALive 6709 - Mosaic 二维线段树

题目链接 给一个n*n的方格, 每个方格有值. 每次询问, 给出三个数x, y, l, 求出以x, y为中心的边长为l的正方形内的最大值与最小值, 输出(maxx+minn)/2, 并将x, y这个格子的值改为(maxx+minn)/2.题目保证l为奇数. 二维线段树的单点更新, 区间查询. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pb(x) push_back(x) 4 #define ll long long 5

HDU1832 二维线段树求最值(模板)

Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 50 Accepted Submission(s): 20   Problem Description 世界上上最远的距离不是相隔天涯海角而是我在你面前可你却不知道我爱你                ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘

UVA 11297 Census ——二维线段树

[题目分析] 二维线段树模板题目. 简直就是无比的暴力.时间复杂度为两个log. 标记的更新方式比较奇特,空间复杂度为N^2. 模板题目. [代码] #include <cstdio> #include <cstring> //#include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <str

Luck and Love(二维线段树)

Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 54 Accepted Submission(s): 21   Problem Description 世界上上最远的距离不是相隔天涯海角而是我在你面前可你却不知道我爱你                ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘

Uva 11297.Census——二维线段树

http://www.bnuoj.com/v3/problem_show.php?pid=19715 二维线段树模板 #include <cstring> #include <cstdio> #include <algorithm> #include <iostream> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define rep(i,n) for(int i=0

HDU 4819 Mosaic (二维线段树)

Problem Description The God of sheep decides to pixelate some pictures (i.e., change them into pictures with mosaic). Here's how he is gonna make it: for each picture, he divides the picture into n x n cells, where each cell is assigned a color value