• 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
    ", d[0]);
        }
        return 0;
    }
    
  • 相关阅读:
    Centos7 下 PHP 添加缺少的组件 sockets 和 openssl
    vue使用 video.js动态切换视频源视频源不刷新问题
    vue+js清除定时器
    获取ip地址,并根据ip获取当前省份
    html页面引用video.js播放m3u8格式视频
    uniapp每隔几秒执行一下网络请求(h5端亲测可以,其他端未测试)
    关于uniapp获取当前距离屏幕顶部的距离
    按值传递与按值引用详解(java版)
    JavaScript的深入理解(1)
    vue-cli3配置webpack-bundle-analyzer插件
  • 原文地址:https://www.cnblogs.com/whx666/p/12041543.html
Copyright © 2020-2023  润新知