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

题意: 给一个矩阵,每次查询一个子矩阵内的最大最小值,然后更新子矩阵中心点为(Max+Min)/2.

解法: 由于是矩阵,且要求区间最大最小和更新单点,很容易想到二维的线段树,可是因为之前没写过二维的线段树,所以没跳出来。后来熟悉了一下,原来很多细节地方都没有考虑到。

这里build,update,query都分为两个函数,第一个为Y轴的(sub_update),第二个为X轴的(update),不仅每个sub_update或sub_build后面要加Y轴的pushup函数,而且每个update或build函数最后也要进行pushup,只不过是X轴的pushup,写成 sub_build(rt,-1,1,n,1) 或 sub_update(rt,-1,1,n,1);

二维线段树就是这里比较费解一点,我感觉, 其他地方还比较好理解。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define Mod 1000000007
#define lll __int64
using namespace std;
#define N 100007

struct sub_seg{
    lll maxi,mini;
};

struct seg{
    sub_seg st[810<<2];
}tt[810<<2];
int n;
lll Max,Min;

void pushup(int xrt,int rt)
{
    tt[xrt].st[rt].maxi = max(tt[xrt].st[rt<<1].maxi,tt[xrt].st[rt<<1|1].maxi);
    tt[xrt].st[rt].mini = min(tt[xrt].st[rt<<1].mini,tt[xrt].st[rt<<1|1].mini);
}

void sub_build(int xrt,int posY,int l,int r,int rt)
{
    if(l == r)
    {
        if(posY != -1)
        {
            scanf("%I64d",&tt[xrt].st[rt].maxi);
            tt[xrt].st[rt].mini = tt[xrt].st[rt].maxi;
        }
        else
        {
            tt[xrt].st[rt].maxi = max(tt[xrt<<1].st[rt].maxi,tt[xrt<<1|1].st[rt].maxi);
            tt[xrt].st[rt].mini = min(tt[xrt<<1].st[rt].mini,tt[xrt<<1|1].st[rt].mini);
        }
         return;
    }
    int mid = (l + r) >> 1;
    sub_build(xrt,posY, l,mid, 2*rt);
    sub_build(xrt,posY, mid+1,r, 2*rt+1);
    pushup(xrt,rt);         //pushup Y
}

void build(int l, int r, int rt)
{
    if(l == r)
    {
        sub_build(rt,l,1,n,1);
        return;
    }
    int mid = (l + r) >> 1;
    build(l,mid,2*rt);
    build(mid+1,r,2*rt+1);
    sub_build(rt,-1,1,n,1);  //pushup X
}

void sub_update(int xrt,int pos,int y,int l,int r,int val,int rt)
{
    if(l == r)
    {
        if(pos!=-1)
            tt[xrt].st[rt].maxi = tt[xrt].st[rt].mini = val;
        else
        {
            tt[xrt].st[rt].maxi = max(tt[xrt<<1].st[rt].maxi,tt[xrt<<1|1].st[rt].maxi);
            tt[xrt].st[rt].mini = min(tt[xrt<<1].st[rt].mini,tt[xrt<<1|1].st[rt].mini);
        }
        return;
    }
    int mid = (l+r) >> 1 ;
    if(y <= mid)  sub_update(xrt, pos, y, l,mid, val, rt<<1) ;
    else          sub_update(xrt, pos, y, mid+1,r, val, rt<<1|1) ;
    pushup(xrt,rt);                     //pushup Y维
}

void update(int x,int y,int l,int r,int val,int rt)  //单点更新
{
    if(l == r)
    {
        sub_update(rt,l,y,1,n,val,1);
        return;
    }
    int mid = (l+r) >> 1;
    if(x<=mid)  update(x,y, l,mid, val, rt<<1);
    else        update(x,y, mid+1,r, val, rt<<1|1);
    sub_update(rt,-1,y,1,n,val,1);      //pushup X维
}

void sub_query(int xrt,int aa,int bb,int l,int r,int rt)
{
    if(aa <= l && bb >= r)
    {
        Max = max(Max,tt[xrt].st[rt].maxi);
        Min = min(Min,tt[xrt].st[rt].mini);
        return;
    }
    int mid = (l+r)>>1;
    if(aa<=mid)  sub_query(xrt,aa,bb,l,mid, rt<<1);
    if(bb>mid)   sub_query(xrt,aa,bb,mid+1,r, rt<<1|1);
}

void query(int l,int r,int aa,int bb,int L1,int R1,int rt)
{
    if(aa <= l && bb >= r)
    {
        sub_query(rt,L1,R1,1,n,1);
        return;
    }
    int mid = (l+r)>>1;
    if(aa <= mid)  query(l,mid,aa,bb,L1,R1, rt<<1);
    if(bb > mid)   query(mid+1,r,aa,bb,L1,R1, rt<<1|1);
}

int main()
{
    int t,i,j,m,x,y,L,cs = 1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        build(1,n,1);
        scanf("%d",&m);
        printf("Case #%d:\n",cs++);
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&L);
            int Lx = max(1,x-L/2);
            int Ly = max(1,y-L/2);
            int Rx = min(n,x+L/2);
            int Ry = min(y+L/2,n);
            Max = -1, Min = Mod;
            query(1,n,Lx,Rx,Ly,Ry,1);
            lll mid = (Max+Min)/2LL;
            printf("%I64d\n",mid);
            update(x,y,1,n,mid,1);
        }
    }
    return 0;
}

时间: 2024-10-18 15:13:43

HDU 4819 Mosaic --二维线段树(树套树)的相关文章

【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[max

树套树+【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

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

HDU 4819 Mosaic 【二维线段树】

题目大意:给你一个n*n的矩阵,每次找到一个点(x,y)周围l*l的子矩阵中的最大值a和最小值b,将(x,y)更新为(a+b)/2 思路:裸的二维线段树 #include<iostream>#include<cstdio>#include <math.h>#include<algorithm>#include<string.h>#include<queue>#define MOD 10000007#define maxn 3500#d

#树套树,二维线段树#HDU 4819 Mosaic

题目 多组数据,给定一个\(n*n\)的矩阵(\(n\leq 80,a_{i,j}\leq 10^9\)) 多组询问一个以\((x,y)\)为中心,边长为\(L\)的子矩阵最大值\(mx\)和最小值\(mn\), 并将\((x,y)\)这一个位置修改为\(\lfloor\frac{mn+mx}{2}\rfloor\),每次询问输出修改后的\((x,y)\) 分析 二维线段树裸题,反正之前也没敲过, 其实和一维线段树相近,找到\(lx\sim rx\)的下标 再按照一维线段树的方式修改最大最小值就

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

HDU 1823 Luck and Love 二维线段树

Problem Description 世界上上最远的距离不是相隔天涯海角 而是我在你面前 可你却不知道我爱你 ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘礼达到500万哦,天哪,可是天文数字了啊,不知多少MM蜂拥而至,顿时万人空巷,连扫地的大妈都来凑热闹来了.―_―||| 由于人数太多,Wiskey实在忙不过来,就把统计的事情全交给了枫冰叶子,自己跑回家休息去了.这可够枫冰叶子忙的了,他要处理的有两类事情,一是得接受MM的报名,二是要帮Wiskey查找符合要求的MM中缘分最

HDU 1823 二维线段树(区间max)

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