zoukankan      html  css  js  c++  java
  • [POI2006]TET-Tetris 3D

    传送门

    要做这道题我们需要两个前置技能:二维线段树和标记永久化。

    我们使用一维线段树来维护一个序列,那我们想维护一个矩阵的时候,二维线段树应运而生。

    二维线段树好像有两种实现方法。一是对于每一个节点(x轴上的每个点)在里面再开一棵线段树(表示一个y轴)(这好像更多人管他叫树套树做法?)

    第二个是把它变成一棵四叉树……不过这种实现方法我并没有学。

    具体的实现方法其实非常优秀,可以选择写结构体。就是对于一次修改,正常在我们一维线段树上传6个参数,我们再多传两个记录y轴修改范围的参数,然后在到达制定修改位置的时候我们进入y轴去修改即可。(这个可以一会看代码)

    之后再说说标记永久化,我们在进行区间修改的时候是要pushdown的,但是这个对于树套树等等比较复杂的数据结构是很麻烦的,而且尤其是像这道题,你不知道怎么下放。所以我们进行标记永久化。以区间加法为例,我们维护sum和add两个标记,在修改到指定位置之前,每经过一个区间就把他的sum加上加的值*区间长度。然后在修改到指定位置(完全覆盖的时候)我们把这个区间的add加上加的值。

    然后在每次之后的查询中,我们每次向下走,都要加上这个区间所贡献的add*区间长度,这样才是结果(注意区间完全覆盖的时候不加,因为这个已经算在sum里面了)

    那我们现在来看这道题。题目翻译的太好了,特别简练,而且是直接告诉你要干啥而不是让你再总结一遍。

    我们用二维线段树维护这个序列。对于每次修改,我们先查询这个矩阵内的最大值,然后直接改成最大值+h的高度就行。

    在途中是可以标记永久化的。这个思路和区间加法是一样的,不过这个变成了永久取最大值,所以在每次下放的时候更新当前mx(最大值),直到区间完全覆盖更新tag(修改后最大值),在query的时候对于一个区间,所有query的值都要与这个区间的tag去比较,然后返回较大值。

    看一下代码。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int N = 8005;
     
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    int d,s,h,x,y,k,n,m;
    
    struct segy//维护y轴
    {
        int mx[N],tag[N];
        void change(int p,int l,int r,int kl,int kr,int val)
        {
            mx[p] = max(mx[p],val);//更新(标记永久化)
            if(l == kl && r == kr)
            {
            tag[p] = max(tag[p],val);//区间完全覆盖的时候更新
            return;
            }
            int mid = (l+r) >> 1;//一切正常
            if(kr <= mid) change(p<<1,l,mid,kl,kr,val);
            else if(kl > mid) change(p<<1|1,mid+1,r,kl,kr,val);
            else change(p<<1,l,mid,kl,mid,val),change(p<<1|1,mid+1,r,mid+1,kr,val);
        }
        int query(int p,int l,int r,int kl,int kr)
        {
            if(l == kl && r == kr) return mx[p];//完全覆盖
            int cur = tag[p],mid = (l+r) >> 1;//剩下的所有与tag比较
            if(kr <= mid) cur = max(query(p<<1,l,mid,kl,kr),cur);
            else if(kl > mid) cur = max(query(p<<1|1,mid+1,r,kl,kr),cur);
            else cur = max(cur,max(query(p<<1,l,mid,kl,mid),query(p<<1|1,mid+1,r,mid+1,kr)));
            return cur;
        }
    };
    
    struct segx//维护x轴
    {
        segy mx[N],tag[N];
        void change(int p,int l,int r,int kl,int kr,int zl,int zr,int val)
        {
            mx[p].change(1,1,m,zl,zr,val);//每次都修改(标记永久化)
            if(l == kl && r == kr)
            {
            tag[p].change(1,1,m,zl,zr,val);//只有完全覆盖才修改
            return;
            }
            int mid = (l+r) >> 1;//剩下的很正常
            if(kr <= mid) change(p<<1,l,mid,kl,kr,zl,zr,val);
            else if(kl > mid) change(p<<1|1,mid+1,r,kl,kr,zl,zr,val);
            else change(p<<1,l,mid,kl,mid,zl,zr,val),change(p<<1|1,mid+1,r,mid+1,kr,zl,zr,val);
        }
        int query(int p,int l,int r,int kl,int kr,int zl,int zr)
        {
            if(l == kl && r == kr) return mx[p].query(1,1,m,zl,zr);
            int cur = tag[p].query(1,1,m,zl,zr),mid = (l+r) >> 1;
            if(kr <= mid) cur = max(cur,query(p<<1,l,mid,kl,kr,zl,zr));
            else if(kl > mid) cur = max(cur,query(p<<1|1,mid+1,r,kl,kr,zl,zr));
            else cur = max(cur,max(query(p<<1,l,mid,kl,mid,zl,zr),query(p<<1|1,mid+1,r,mid+1,kr,zl,zr)));
            return cur;//这里每次在修改的时候都要与tag比较,完全覆盖的时候不用,因为已经更新过了
        }
    }t;
    
    int main()
    {
        n = read(),m = read(),k = read();
        while(k--)
        {
        d = read(),s = read(),h = read(),x = read(),y = read();
        int g = t.query(1,1,n,x+1,x+d,y+1,y+s);//查询最大值
        t.change(1,1,n,x+1,x+d,y+1,y+s,g+h);//区间修改
        }
        printf("%d
    ",t.query(1,1,n,1,n,1,m));
        return 0;
    }
  • 相关阅读:
    Java实现OPC通信
    OPCServer:使用KEPServer
    OPCServer:使用Matrikon OPC Server Simulation
    OPC和DCOM配置
    jquery中attr和prop的区别
    jquery 操作checkbox是否选中的正确方法
    GPRS RTU设备OPC Server接口C# 实现
    Raspberry Pi 中安装Mono
    C#中DllImport用法汇总
    HTML <form> 标签的 method 属性
  • 原文地址:https://www.cnblogs.com/captain1/p/9746364.html
Copyright © 2011-2022 走看看