[2018]ラインチームワーク

あなたが貢献のために考慮することができる前に、DP方程式は、非常に簡単です。

\(のf_i = \ MIN_ {L_iを\当量J <i}は\ {F_J + \左(\ MAX_ {J <K \当量I} \左\ {T_K \右\} \右)\回\左(\左sum_ {k = I + 1} ^ N w_k \右)\右\} \)\

\(O \左(N ^ 2 \右)\) 明らかに。\(W \)サフィックスとデクリメント、\(\最大T \)見かけの単調性の最適化を単調増加を残しました。

単調スタック\(\最大tが\)凸包セクションを維持するために、クエリの必要性、セクションに分かれています。単調なスタックは終わりの挿入をサポートする必要があるため、間隔がクエリ凸包、非常に厄介な、終わりを削除します。

たくさんの練習は、自分の位置を学びます。(もちろんダイナミック凸船体ああを書くつもりではありません)

挿入や削除凸船体部分は一般的なサポート、以下のプラクティスの最後に質問をするために:

(さまざまなトピックの非常に多くの場合、自然、ないの複雑さを慎重に分析ので)

ツリー方法

木が単調スタック、ポップアップジャンプFAとなり、ジャンプ息子を挿入し、クエリは、チェーンの木です。

点線ルール

それぞれのサブツリーのクエリの重心を通る二本鎖へテロゲーション分割、および凸包ヒューリスティックマージ。

ツリーパーティションを根ざしがあるようです。しかし、その後、チェーンは以下の罰金に貢献し、直接単調なキュー上に構築されました。

Treeセクション

各鎖メンテナンスセグメントツリーの直接の断面木、。

バランスのとれたツリー

ノードが考慮この間隔の範囲、そしてバインドバランスの取れた木の半分を挿入したときに、新しいノードを削除する時間をノードを削除します。

だから、新しいノードが削除されたときに、元の範囲に戻ります。

バイナリパケット

遅延再建通常のトリック?

セグメントツリーとバイナリパケットを維持することは、削除されたマーキングルートに、唯一の右のチェーンは、各グループのタグを維持することは非常に簡単です。

クエリタグを持っている場合は、再帰的に二人の息子。

挿入された基が結合されてもよい場合サブツリーをマークした場合、再構成は、再帰的であることができます。

ポテンシャルエネルギー波の分析は、削除しても過言ではない再構築しました。

タイムスタンプセグメントツリー

良い点を置くために直接範囲を削除しないでください。


私はファットバイナリパケットを書きました。横軸の単調クエリとして組み合わせた線形複雑度、とても単調キュー。時間と空間のログ。

間違ったシンボルにつながる、間違った方向を描画するための外積を描画する際に考慮し、巨大な長いが出て撮影する倒す...... / PX

#include <bits/stdc++.h>

const int MAXN = 100010;
typedef long long LL;
typedef long double LD;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
typedef std::vector<int> VI;
void getmin(LL & x, LL y) { x > y ? x = y : 0; }
int n, ls[MAXN], ts[MAXN], ws[MAXN];
LL suc[MAXN], dp[MAXN];
int st[MAXN], top, vs[MAXN];
namespace ch {
    int tag[MAXN << 2], at[MAXN], sz[MAXN << 2];
    void build(int u, int l, int r) {
        sz[u] = r - l + 1;
        if (l == r) return (void) (at[l] = u);
        int mid = l + r >> 1;
        build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r);
    }
    LL ks[MAXN], bs[MAXN]; int bak;
    bool chk(int a, int b, LL at) {
        return (LD) ks[a] * at + bs[a] >= (LD) ks[b] * at + bs[b];
    }
    bool cross(LL x1, LL y1, LL x2, LL y2) {
        return (LD) x1 * y2 - (LD) x2 * y1 >= -1e-10;
    }
    bool cmp(int a, int b, int c) {
        return cross(ks[b] - ks[a], bs[b] - bs[a], ks[c] - ks[a], bs[c] - bs[a]);
    }
    struct monoq {
        VI que; int b, e;
        void set(int at) { que.clear(); que.push_back(at); b = e = 0; }
        void merge(const monoq & a, const monoq & b) {
            int ta = a.b, tb = b.b;
            static int st[MAXN], top, now; top = 0;
            for (int T = a.e - ta + b.e - tb + 2; T; --T) {
                if (ta <= a.e && (tb > b.e || ks[a.que[ta]] >= ks[b.que[tb]]))
                    now = a.que[ta++];
                else now = b.que[tb++];
                while (top > 1 && cmp(st[top - 1], st[top], now)) --top; 
                st[++top] = now;
            }
            que.assign(st + 1, st + top + 1);
            this -> b = 0, e = top - 1;
        }
        LL qry(LL at) {
            while (e - b + 1 >= 2 && chk(que[b], que[b + 1], at)) ++b;
            return ks[que[b]] * at + bs[que[b]];
        }
    } tree[MAXN << 2];
    LL exqry(int u, LL at) {
        if (!tag[u])
            return std::min(exqry(u << 1, at), exqry(u << 1 | 1, at));
        return tree[u].qry(at);
    }
    LL query(int u, int l, int r, int L, int R, LL at) {
        if (L <= l && r <= R) return exqry(u, at);
        int mid = l + r >> 1; LL res = INFL;
        if (L <= mid) res = query(u << 1, l, mid, L, R, at);
        if (mid < R) res = std::min(res, query(u << 1 | 1, mid + 1, r, L, R, at));
        return res;
    }
    LL qry(LL at, int L) { return query(1, 1, n, L, bak, at); }
    void rebuild(int u) {
        if (tag[u]) return ;
        if (!sz[u << 1] && !sz[u << 1 | 1]) {
            rebuild(u << 1); rebuild(u << 1 | 1);
            tag[u] = true;
            tree[u].merge(tree[u << 1], tree[u << 1 | 1]);
        }
    }
    void push_back(LL k, LL b) {
        int u = at[++bak];
        ks[bak] = k, bs[bak] = b;
        tree[u].set(bak); tag[u] = true;
        while (u) {
            --sz[u], u >>= 1;
            if (u) rebuild(u);
        }
    }
    void pop_back() {
        int u = at[bak--];
        while (u) ++sz[u], tag[u] = false, u >>= 1;
    }
}
struct segmenttree {
    LL tree[MAXN << 2];
    void mdf(int u, int l, int r, int tar, LL v) {
        if (l == r) return (void) (tree[u] = v);
        int mid = l + r >> 1;
        if (tar <= mid) mdf(u << 1, l, mid, tar, v);
        else mdf(u << 1 | 1, mid + 1, r, tar, v);
        tree[u] = std::min(tree[u << 1], tree[u << 1 | 1]);
    }
    LL qry(int u, int l, int r, int L, int R) {
        if (L <= l && r <= R) return tree[u];
        int mid = l + r >> 1; LL res = INFL;
        if (L <= mid) res = qry(u << 1, l, mid, L, R);
        if (mid < R) res = std::min(res, qry(u << 1 | 1, mid + 1, r, L, R));
        return res;
    }
    LL qry(int l, int r) { return l > r ? INFL : qry(1, 0, n, l, r); }
} seg;
int main() {
    std::ios_base::sync_with_stdio(false), std::cin.tie(0);
    std::cin >> n;
    ch::build(1, 1, n);
    for (int i = 1; i <= n; ++i)
        std::cin >> ls[i] >> ts[i] >> ws[i];
    for (int i = n; i; --i) suc[i] = suc[i + 1] + ws[i];
    memset(dp, 0x3f, n + 1 << 3);
    seg.mdf(1, 0, n, 0, dp[0] = 0);
    for (int i = 1; i <= n; ++i) {
        while (top && vs[top] <= ts[i])
            --top, ch::pop_back();
        int l = st[top] + 1;
        st[++top] = i, vs[top] = ts[i];
        ch::push_back(ts[i], seg.qry(l - 1, i - 1));
        int tl = std::lower_bound(st + 1, st + 1 + top, ls[i]) - st;
        LL t = seg.qry(ls[i], st[tl] - 1);
        getmin(dp[i], t + suc[i + 1] * vs[tl]);
        if (tl < top) getmin(dp[i], ch::qry(suc[i + 1], tl + 1));
        seg.mdf(1, 0, n, i, dp[i]);
    }
    std::cout << dp[n] << std::endl;
    return 0;
}

おすすめ

転載: www.cnblogs.com/daklqw/p/11896860.html