POI2006-BZOJ1513:Tet-Tetris 3D

这里写图片描述
题意:给定一个空矩阵,对其进行两种操作:
1.矩阵询问max
2.矩阵赋值
你只需要输出最后的矩阵最大值。
二维线段树……应该是显然的,但是做的时候发现自己Naive了……
首先我们在修改一个子矩阵时,包含子矩阵的那些矩阵的值在外层没办法上传。
其次我们发现子矩阵的子矩阵也没有信息……
忽然想到标记永久化这个东西,想到一种方法大概这样:
比较显然的一点就是,内外层线段树是等效的,所以我们只要不在外层上传信息,下传信息,就”不必“在内层下传信息。
1.在每层线段树我们记录两个值,一个值是完美覆盖该区间的标记Tag,一个值是子树最大值Mx。
我们在修改的时候,可以这样做:
对于外层线段树上的那条修改路径,由于其修改是单增不降的,所以我们可以直接更改那条路径上的Mx,直到修改到某个节点,它被这个修改区间覆盖,这时候我们不仅要修改子树的值,还需要修改它的Tag。
所以,对于修改,我们只需要对于每层的线段树沿途也进行修改即可。
2.对于查询最大值:
我们在查询某个子矩阵的最大值的时候,在路径上显然要查询所有路径上的Tag,对于某个被询问区间覆盖的区间,我们需要查询它的子树值,最后对所有值取max。
特别注意,如果没有特别的数据弱,我们里层需要动态开点。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#define Rep(i,n) for(int i = 1; i <= n ; i ++)
#define RepG(i,x) for(int i = head[x] ;~ i ; i = edge[i].next)
#define Rep_d(i,n) for(int i = n ; i > 0 ; i --)
#define Rep_0(i,n) for(int i = 0 ; i < n ; i ++)
#define RD(i,x,n) for(int i = x; i <= n ; i ++)
#define CLR(a,b) memset(a,b,sizeof(a))
#define RDD(i,x,n) for(int i = x; i >= n; i --)
#define u t[x]
#define lc ch[0]
#define rc ch[1]
#define v edge[i].to
#define ulfc t[u.lc]
#define urtc t[u.rc]
using namespace std;
const int inf = 1 << 30;
typedef long long ll;
int read(){
    char ch = getchar();
    while((ch < '0' || ch > '9') && ch != '-')ch = getchar ();
    int x = 0;
    bool flag = 0;
    if(ch == '-')ch = getchar(),flag = 1;
    while(ch >= '0' && ch <= '9')x = (x << 1) + (x << 3) + ch - '0',ch = getchar ();
    return flag ? -x : x;
}
const int N = 1005;
int n,m,k;
#define lson x << 1,l,mid,ql,qr
#define rson x << 1 | 1,mid + 1,r,ql,qr
#define RT 1,1,n,ql,qr 
int Ql,Qr;
struct Seg{
    struct Tree{
        int Mx[N * 3],tag[N * 3];
        void Modify(int x,int l,int r,int ql,int qr,int s){
            Mx[x] = max(Mx[x],s);
            if(l >= ql && r <= qr){
                tag[x] = max(s,tag[x]);
                return ;
            }
            int mid = l + r >> 1;
            if(ql <= mid)Modify(lson,s);
            if(mid < qr)Modify(rson,s);
        }
        int Qry(int x,int l,int r,int ql,int qr){
            if(l >= ql && r <= qr)return Mx[x];
            int ans = tag[x],mid = l + r >> 1;
            if(ql <= mid)ans = max(Qry(lson),ans);
            if(mid < qr)ans = max(Qry(rson),ans);
            return ans;
        }
    };
    Tree Mx[N * 3],tag[N * 3];
    void Modify(int x,int l,int r,int ql,int qr,int s){
        Mx[x].Modify(RT,s);
        if(l >= Ql && r <= Qr){
            tag[x].Modify(RT,s);
            return ;
        }
        int mid = l + r >> 1;
        if(Ql <= mid)Modify(lson,s);
        if(mid < Qr)Modify(rson,s);
    }
    int Qry(int x,int l,int r,int ql,int qr){
        if(l >= Ql && r <= Qr)
            return Mx[x].Qry(RT);
        int ans = tag[x].Qry(RT),mid = l + r >> 1;
        if(Ql <= mid)ans = max(ans,Qry(lson));
        if(mid < Qr)ans = max(ans,Qry(rson));
        return ans;
    }
}seg;
int main (){
    n = read(),m = read(),k = read();
    Rep(i,k)
    {
        int len,wd,ht,x,y;
        len = read(),wd = read(),ht = read(),x = read(),y = read();
        Ql = x + 1;
        Qr = x + len;
        int p;
        p = seg.Qry(1,1,n,y + 1,y + wd);
        seg.Modify(1,1,n,y + 1,y + wd,p + ht);
    }
    Ql = 1,Qr = n;
    printf("%d\n",seg.Qry(1,1,n,1,n));
    return 0;
}
/*
7 5 4

4 3 2 0 0

3 3 1 3 0

7 1 2 0 3

2 3 3 2 2
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值