1. 程式人生 > >hdu 3016 Man Down(線段樹區間更新+dp)

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; }