HDU3016 Man Down 题解
HDU3016 Man Down】
题意:在平面内有n条横放的线段,每条线段给出高度、左右端点位置和能量(可正可负),最初处于最高的一条线段上且拥有100点能量和当前线段上的能量之和,每次可以从线段左边或右边竖直落下(可能落到其他线段上也可能落到地上),落到其他线段上则获得线段上能量并继续游戏,若落到地上则终止游戏,得分为当前能量之和。但任意一个时刻能量必须为正,当能量<=0时就失败了,终止游戏。若能落到地上,输出最大得分,若不能输出-1
这题我的方法比较奇特(傻)
假设地面为0号线段,每条的线段都会指向另外两条线段(从左右端点落下时到达线段),可以看作线段之间连了一条又向边,边的长度可以用到达的线段上的能量表示,这样就建出了一张有向图,跑Spfa求出最高线段到0号的最长路即为答案(其实这个问题用dp解决就好了,dp写法看这里)
关键在于求出每条线段从左右两段落下后会到达哪两条线段:上面的线段可以覆盖下面的,所以按高度从低到高排序,依次更新、查询就可以求出两条线段的编号。举个例子,当前线段已经按高度排序,处理到一条左端点为5,右端点为10的线段i时,先在线段树中单点查询5、10,然后将5——10的区间值修改为i
#include <bits/stdc++.h>
using namespace std;
inline void read (int &x) {
char ch = getchar(); int f = 0; x = 0;
while (!isdigit(ch)) {if (ch == '-') f = 1; ch = getchar();}
while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
if (f) x = -x;
}
const int N = 1E5 + 10;
int n, cnt, M, c[N << 2], d[N], to[N][2], vis[N];
struct e {
int h, l, r, val;
bool operator < (const e &x) const {return h < x.h;}
} a[N];
#define ls p << 1
#define rs p << 1 | 1
inline void push_down (int p) {
if (c[p]) c[ls] = c[rs] = c[p], c[p] = 0;
}
int update (int p, int l, int r, int ql, int qr, int val) {
if (ql <= l && qr >= r) {c[p] = val; return 0;}
push_down (p);
int mid (l + r >> 1);
if (ql <= mid) update (ls, l, mid, ql, qr, val);
if (qr > mid) update (rs, mid + 1, r, ql, qr, val);
}
int query (int p, int l, int r, int pos) {
if (l == r) return c[p];
push_down (p);
int mid (l + r >> 1);
return pos <= mid ? query (ls, l, mid, pos) : query (rs, mid + 1, r, pos);
}
inline void Spfa () {
queue <int> q;
memset (d, 0xcf, sizeof (d));
memset (vis, 0, sizeof (vis));
d[n] = 100 + a[n].val, vis[n] = 1, q.push (n);
while (!q.empty()) {
int u = q.front ();
vis[u] = 0, q.pop ();
for (int i = 0; i <= 1; ++i) {
int v = to[u][i];
if (d[u] + a[v].val > d[v] && d[u] + a[v].val > 0) {
d[v] = d[u] + a[v].val;
if (!vis[v]) q.push (v), vis[v] = 1;
}
}
}
}
int main() {
while (~scanf ("%d", &n)) {
cnt = M = 0;
memset (c, 0, sizeof (c));
for (int i = 1; i <= n; ++i)
read (a[i].h), read (a[i].l), read (a[i].r), read (a[i].val), M = max (M, a[i].r);
sort (a + 1, a + n + 1);
for (int i = 1; i <= n; ++i) {
int tl = query (1, 1, M, a[i].l), tr = query (1, 1, M, a[i].r);
to[i][0] = tl, to[i][1] = tr;
update (1, 1, M, a[i].l, a[i].r, i);
}
Spfa ();
if (d[0] < 0) puts ("-1");
else printf ("%d\n", d[0]);
}
return 0;
}