HDU3016 Man Down 题解

Posted whx666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU3016 Man Down 题解相关的知识,希望对你有一定的参考价值。

HDU3016 Man Down

线段树例题解析合集

题意:在平面内有n条横放的线段,每条线段给出高度、左右端点位置和能量(可正可负),最初处于最高的一条线段上且拥有100点能量和当前线段上的能量之和,每次可以从线段左边或右边竖直落下(可能落到其他线段上也可能落到地上),落到其他线段上则获得线段上能量并继续游戏,若落到地上则终止游戏,得分为当前能量之和。但任意一个时刻能量必须为正,当能量<=0时就失败了,终止游戏。若能落到地上,输出最大得分,若不能输出-1

这题我的方法比较奇特(傻)

假设地面为0号线段,每条的线段都会指向另外两条线段(从左右端点落下时到达线段),可以看作线段之间连了一条又向边,边的长度可以用到达的线段上的能量表示,这样就建出了一张有向图,跑Spfa求出最高线段到0号的最长路即为答案(其实这个问题用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
", d[0]);
    }
    return 0;
}

以上是关于HDU3016 Man Down 题解的主要内容,如果未能解决你的问题,请参考以下文章

hdu 3016 Man Down

[HDU2577]How to Type(DP)

hdu 5381

HDU5653 Bomber Man wants to bomb an Array 简单DP

HDU4801 转魔方DFS模拟

Man Down(线段树dp)