【BZOJ】1513: [POI2006]Tet-Tetris 3D

题意

\(n(1 \le n \le 20000)\)个立方体\((x, y, z)\),依次落下。求所有立方体落下完了以后最高的高度。

分析

平面求最大值,平面更新最大值。

题解

二维线段树走起,由于不好自下往上更新而且发现更新的时候值是越来越大,所以我们可以在每一次更新的时候直接在走过的路径上更新一下最大值(or第二维线段树)即可。

#include <bits/stdc++.h>
using namespace std;
inline int getint() {
    int x=0, c=getchar();
    for(; c<48||c>57; c=getchar());
    for(; c>47&&c<58; x=x*10+c-48, c=getchar());
    return x;
}
inline void U(int &a, int b) {
    a=max(a, b);
}
const int N=2105;
int n, m, q;
struct T1 {
    int w[N], tag[N];
    void upd(int L, int R, int g, int l=1, int r=m, int x=1) {
        U(w[x], g);
        if(L<=l && r<=R) {
            U(tag[x], g);
            return;
        }
        int mid=(l+r)>>1;
        if(L<=mid) {
            upd(L, R, g, l, mid, x<<1);
        }
        if(mid<R) {
            upd(L, R, g, mid+1, r, x<<1|1);
        }
    }
    int ask(int L, int R, int l=1, int r=m, int x=1) {
        if(L<=l && r<=R) {
            return w[x];
        }
        int mid=(l+r)>>1, y=tag[x];
        if(L<=mid) {
            U(y, ask(L, R, l, mid, x<<1));
        }
        if(mid<R) {
            U(y, ask(L, R, mid+1, r, x<<1|1));
        }
        return y;
    }
};
struct T2 {
    T1 w[N], tag[N];
    void upd(int L, int R, int LL, int RR, int g, int l=1, int r=n, int x=1) {
        w[x].upd(LL, RR, g);
        if(L<=l && r<=R) {
            tag[x].upd(LL, RR, g);
            return;
        }
        int mid=(l+r)>>1;
        if(L<=mid) {
            upd(L, R, LL, RR, g, l, mid, x<<1);
        }
        if(mid<R) {
            upd(L, R, LL, RR, g, mid+1, r, x<<1|1);
        }
    }
    int ask(int L, int R, int LL, int RR, int l=1, int r=n, int x=1) {
        if(L<=l && r<=R) {
            return w[x].ask(LL, RR);
        }
        int mid=(l+r)>>1, y=tag[x].ask(LL, RR);
        if(L<=mid) {
            U(y, ask(L, R, LL, RR, l, mid, x<<1));
        }
        if(mid<R) {
            U(y, ask(L, R, LL, RR, mid+1, r, x<<1|1));
        }
        return y;
    }
}t;

int main() {
    n=getint(), m=getint(), q=getint();
    for(; q--; ) {
        int d=getint(), s=getint(), w=getint(), x=getint(), y=getint();
        ++x, ++y;
        t.upd(x, x+d-1, y, y+s-1, t.ask(x, x+d-1, y, y+s-1)+w);
    }
    printf("%d\n", t.ask(1, n, 1, m));
    return 0;
}

转载于:https://www.cnblogs.com/iwtwiioi/p/4985682.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值