洛谷【P3437】[POI2006]TET-Tetris 3D

浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html

浅谈标记永久化:https://www.cnblogs.com/AKMer/p/10137227.html

题目传送门:https://www.luogu.org/problemnew/show/P3437

位置线段树套位置线段树,支持区间询问最大值和区间取\(max\)操作。

标记永久化,每次询问把区间内最大值和覆盖这个区间的标记取\(max\)即可。

时间复杂度:\(O(NlogDlogS)\)

空间复杂度:\(O(DS)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn=1005;

int D,S,N;

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

struct segment_treeS {
    int mx[maxn<<2],tag[maxn<<2];

    void change(int p,int l,int r,int L,int R,int v) {
        mx[p]=max(mx[p],v);
        if(L<=l&&r<=R) {tag[p]=max(tag[p],v);return;}
        int mid=(l+r)>>1;
        if(L<=mid)change(p<<1,l,mid,L,R,v);
        if(R>mid)change(p<<1|1,mid+1,r,L,R,v);
    }

    int query(int p,int l,int r,int L,int R) {
        if(L<=l&&r<=R)return mx[p];
        int mid=(l+r)>>1,res=tag[p];
        if(L<=mid)res=max(res,query(p<<1,l,mid,L,R));
        if(R>mid)res=max(res,query(p<<1|1,mid+1,r,L,R));
        return res;
    }
};

struct segment_treeD {
    segment_treeS mx[maxn<<2],tag[maxn<<2];
    
    int query(int p,int l,int r,int x1,int x2,int y1,int y2) {
        if(x1<=l&&r<=x2)return mx[p].query(1,0,S-1,y1,y2);
        int mid=(l+r)>>1,res=tag[p].query(1,0,S-1,y1,y2);
        if(x1<=mid)res=max(res,query(p<<1,l,mid,x1,x2,y1,y2));
        if(x2>mid)res=max(res,query(p<<1|1,mid+1,r,x1,x2,y1,y2));
        return res;
    }

    void change(int p,int l,int r,int x1,int x2,int y1,int y2,int v) {
        mx[p].change(1,0,S-1,y1,y2,v);
        if(x1<=l&&r<=x2) {tag[p].change(1,0,S-1,y1,y2,v);return;}
        int mid=(l+r)>>1;
        if(x1<=mid)change(p<<1,l,mid,x1,x2,y1,y2,v);
        if(x2>mid)change(p<<1|1,mid+1,r,x1,x2,y1,y2,v);
    }
}T;

int main() {
    D=read(),S=read(),N=read();
    for(int i=1;i<=N;i++) {
        int d=read(),s=read(),w=read(),x=read(),y=read();
        int mx=T.query(1,0,D-1,x,x+d-1,y,y+s-1);
        T.change(1,0,D-1,x,x+d-1,y,y+s-1,mx+w);
    }
    printf("%d\n",T.query(1,0,D-1,0,D-1,0,S-1));
    return 0;
}

转载于:https://www.cnblogs.com/AKMer/p/10135481.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值