[HDU3842]Machine Works

題目鏈接HDU3842

題目大意
N1e5 臺機器,允許在Di 天以Pi 元買入,任意天以Ri 元賣出;若你擁有某一個機器,你就不能擁有另外的機器;在你擁有某臺機器的時候,你每天會獲得Gi 的收入;在你買入一臺機器或賣出一臺機器的時候,機器不能工作,但是你可以在同一天賣出一臺並買入另一臺。
若你一開始有X 元,到第D+1 天爲止,你能獲利多少,且D+1 天你必須賣出你所擁有的機器

題目分析
1. 斜率優化DP,先對時間排序。
2. 設F(x)=dp[x]DxGxGx+Rx ,維護對於任意Dj>Dk ,有F(j)F(k)DjDkDi ,i爲當前處理的點。
3. 由於Dx 不單調,用Splay維護凸殼。

上代碼

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long double DB;
typedef long long LL;
const LL N = 1e5 + 10;
const LL INF = 0x3f3f3f3f;

LL n;
inline LL read() {
    char ch;
    LL ans = 0, neg = 1LL;
    while (!isdigit(ch = getchar()))
        if (ch == '-') neg = -1;
    while (isdigit(ch))
        ans = ans * 10 + ch - '0', ch = getchar();
    return ans * neg;
}

struct Mac {
    LL D, P, R, G;
    inline void input() {
        D = read(), P = read(), R = read(), G = read();
    }
    inline bool operator < (const Mac &a) const {
        return D < a.D;
    }
} mac[N];

LL root, cnt;
LL fa[N], ch[N][2], size[N], plc[N];
#define lc(a) (ch[a][0])
#define rc(a) (ch[a][1])
#define csk(a) (ch[fa[a]][1] == a)
#define makeLink(a, b, c) fa[ch[a][c] = b] = a
#define isRoot(a) (ch[fa[a]][0] != a && ch[fa[a]][1] != a)
inline void update(LL a) {
    size[a] = 1;
    if (lc(a)) size[a] += size[lc(a)];
    if (rc(a)) size[a] += size[rc(a)];
}
inline void rotate(LL a) {
    LL c = csk(a), f = fa[a];
    makeLink(f, ch[a][c ^ 1], c);
    if (isRoot(f)) fa[a] = fa[f];
    else makeLink(fa[f], a, csk(f));
    makeLink(a, f, c ^ 1), update(f), update(a);
}
void splay(LL a, LL dst) {
    while (fa[a] != dst) {
        if (fa[fa[a]] != dst) {
            if (csk(fa[a]) == csk(a)) rotate(fa[a]);
            else rotate(a);
        } rotate(a);
    }
    if (!fa[a]) root = a;
}
inline LL getPre(LL a) {
    splay(a, 0), a = lc(a);
    while (rc(a)) a = rc(a);
    return a;
}
inline LL getNxt(LL a) {
    splay(a, 0), a = rc(a);
    while (lc(a)) a = lc(a);
    return a;
}
inline LL getVal(LL a) {
    if (a == 1) return 0;
    if (a == 2) return INF;
    return mac[plc[a]].G;
}
inline LL insert(LL a) {
    LL id = ++cnt; plc[id] = a;
    LL tmp = root;
    while (!fa[id]) {
        if (getVal(tmp) <= getVal(id))
            if (rc(tmp)) tmp = rc(tmp);
            else makeLink(tmp, id, 1);
        else
            if (lc(tmp)) tmp = lc(tmp);
            else makeLink(tmp, id, 0);
    }
    while (update(tmp), !isRoot(tmp)) tmp = fa[tmp];
    return id;
}
inline void delett(LL a) {
    LL pre = getPre(a), nxt = getNxt(a);
    splay(pre, 0), splay(nxt, root);
    lc(nxt) = 0, update(nxt), update(pre);
}

LL dp[N];
#define ff(a) (dp[a] - mac[a].D * mac[a].G - mac[a].G + mac[a].R)
inline DB calcK(LL a, LL b) {
//    cout << ff(a) << " " << ff(b) << endl;
    if (mac[a].G == mac[b].G)
        return ff(a) - ff(b) > 0 ? -INF : INF;
    return (DB)(ff(a) - ff(b)) / (mac[a].G - mac[b].G);
}
inline bool judge(LL a) {
    LL pre = getPre(a), nxt = getNxt(a);
    if (pre == 1 || nxt == 2) return true;
    if (calcK(plc[pre], plc[a]) <= calcK(plc[a], plc[nxt]))
        return false;
    return true;
}
int main() {
    LL T = 0;
    while (++T) {
        memset(fa, 0, sizeof(fa));
        memset(ch, 0, sizeof(ch));
        n = read(), dp[0] = read();
        mac[n + 1].D = read() + 1;
        mac[n + 1].P = mac[n + 1].R = mac[n + 1].G = 0;
        if (!n && !dp[0] && mac[n + 1].D == 1) break;
        cnt = 2, makeLink(1, 2, 1), update(root = 1), insert(0);
        printf("Case %lld: ", T);
        for (LL i = 1; i <= n; i++) mac[i].input();
        sort(mac + 1, mac + n + 2);
        for (LL i = 1; i <= n + 1; i++) {
            while (size[root] > 3) {
                LL a = getNxt(1), b = getNxt(a);
                if (calcK(plc[a], plc[b]) >= -mac[i].D) delett(a);
                else break;
            }
            LL tmp = plc[getNxt(1)];
            dp[i] = ff(tmp) + mac[i].D * mac[tmp].G - mac[i].P;
        //    cout << i << " " << tmp << endl;
            if (dp[i] < 0) continue;
            if (tmp = insert(i), judge(tmp)) {
                LL now = 0;
                while (plc[now = getPre(tmp)] && !judge(now))
                    delett(now);
                while (plc[now = getNxt(tmp)] && !judge(now))
                    delett(now);
            } else delett(tmp);
        }
        printf("%lld\n", dp[n + 1]);
    }
    return 0;
}

以上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章