hdu 3016 Man Down(线段树区间更新+dp)

题意:

是男人就下100层相信很多人都玩过,这题就是简单的模拟这个游戏。
n 块木板,每块木板有4个属性,高h(h>0),左边界,右边界,以及掉落在它上面,获得多少生命值,一个人从最高的木板开始往下跳,初始时生命值为100,问最后掉落到地面能获得的生命值最多为多少(如果途中生命值为≤0,那么这个人会死去),如果无法跳到地面,输出-1。

解析:

既然只能垂直下落,而且是落在最近的板上,所以其实下落后处于哪个木板是唯一确定的。
所以我们可以逆向考虑,对于任意一块木板,这块木板,可以接到从哪一块木板上面落下来的物体。
这里可以借助线段树。先将木板按 h 从小到大排序,初始时,更新线段树里的全部节点为地面的下标,然后往上添加木板的过程就是,单点查询每个木板的左端点和右端点,得到的下标就是当前木板能转移到的其他木板(或者地面),然后将这段区间更新为当前木板的下标。
这样就可以得到每块木板可以落到哪一块木板上了。

然后就是利用 dp ,求最大的权值总和,状态转移方程为:
d[line[i].lv]=max(d[line[i].lv],d[i]+line[line[i].lv].val);
d[line[i].rv]=max(d[line[i].rv],d[i]+line[line[i].rv].val);

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
#define MID (L + R) >> 1
using namespace std;
const int N = (int)1e5 + 10;
const int INF = 0x3f3f3f3f;
int n;

struct Line {
    int h, l, r, val;
    int lv, rv;
    bool operator < (const Line& rhs) const {
        return h < rhs.h;
    }
} line[N];

int cov[N<<2];
inline void pushDown(int o) {
    if(cov[o] != -1) {
        cov[ls] = cov[rs] = cov[o];
        cov[o] = -1;
    }
}

inline void pushUp(int o) {
    if(cov[ls] == cov[rs])
        cov[o] = cov[ls];
    else cov[o] = -1;
}

void modify(int o, int L, int R, int ql, int qr, int val) {
    if(ql <= L && R <= qr) {
        cov[o] = val;
        return ;
    }
    int M = MID;
    pushDown(o);
    if(ql <= M) modify(lson, ql, qr, val);
    if(qr > M) modify(rson, ql, qr, val);
    pushUp(o);
}

int query(int o, int L, int R, int pos) {
    if(L == R) return cov[o];
    int M = MID;
    pushDown(o);
    if(pos <= M) return query(lson, pos);
    else return query(rson, pos);
}

int d[N];
int main() {
    int h, l, r, val;
    int ql, qr;
    while(~scanf("%d", &n)) {
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d%d", &h, &l, &r, &val);
            line[i] = (Line){h, l, r, val};
        }

        sort(line+1, line+n+1);
        modify(1, 0, N, 0, N, 0);
        for(int i = 1; i <= n; i++) {
            line[i].lv = query(1, 0, N, line[i].l);
            line[i].rv = query(1, 0, N, line[i].r);
            modify(1, 0, N, line[i].l, line[i].r, i);
        }

        memset(d, 0, sizeof(d));
        d[n] = 100 + line[n].val;
        for(int i = n; i > 0; i--){
            if(d[i] <= 0) continue;
            d[line[i].lv]=max(d[line[i].lv], d[i]+line[line[i].lv].val);
            d[line[i].rv]=max(d[line[i].rv], d[i]+line[line[i].rv].val);
        }
        printf("%d\n",d[0] > 0 ? d[0] : -1);
    }
    return 0;
}

你可能感兴趣的:(HDU,3016)