Submission #1331313

#TimeUsernameProblemLanguageResultExecution timeMemory
1331313witek_cppBuilding Bridges (CEOI17_building)C++20
100 / 100
48 ms6616 KiB
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

#define st first
#define nd second
#define pb push_back
#define all(a) a.begin(), a.end()
#define sz(a) int(a.size())
#define f(i, a, b) for (int i = a; i < b; i++)
#define rep(i, a) f(i, 0, a)
#define int ll
#define tv(a, x) for (auto& a : x)
#define DUZO 1000000000000000000LL
#define en "\n"
using pii = pair<int, int>;
using vi = vector<int>;
using vvi = vector<vi>;
using vii = vector<pii>;

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

#define st first
#define nd second
#define pb push_back
#define all(a) a.begin(), a.end()
#define sz(a) int(a.size())
#define f(i, a, b) for (int i = a; i < b; i++)
#define rep(i, a) f(i, 0, a)
#define int ll
#define tv(a, x) for (auto& a : x)
#define DUZO 1000000000000000000LL
#define en "\n"
using pii = pair<int, int>;
using vi = vector<int>;
using vvi = vector<vi>;
using vii = vector<pii>;

struct cht {
    struct Line {
        ll k, b;
        Line(ll kk=0, ll bb=(ll)4e18): k(kk), b(bb) {}
        inline ll eval(ll x) const {
            __int128 v = (__int128)k * x + (__int128)b;
            return (ll)v;
        }
    };

    struct Node {
        Line line;
        int l = -1, r = -1;
    };

    vector<Node> st;
    ll L, R;

    // konstruktor: zakres [l, r] (inclusive)
    cht(ll l = 0, ll r = 1000000) {
        L = l; R = r;
        st.reserve(1<<20);
        st.clear();
        st.push_back(Node());
        st[0].line = Line(0, (ll)4e18);
    }

    int newNode() {
        st.push_back(Node());
        st.back().line = Line(0, (ll)4e18);
        return (int)st.size() - 1;
    }

    // wewnętrzna funkcja dodająca linię (Line nw) do poddrzewa idx reprezentującego [l, r]
    void add_line_internal(int idx, ll l, ll r, const Line &nw) {
        ll m = (l + r) >> 1;
        Line lo = st[idx].line;
        Line hi = nw;

        // upewniamy się, że lo(l) <= hi(l)
        if (lo.eval(l) > hi.eval(l)) swap(lo, hi);
        // jeżeli lo <= hi na całym przedziale -> zachowujemy lo
        if (lo.eval(r) <= hi.eval(r)) {
            st[idx].line = lo;
            return;
        }

        // w przeciwnym razie musimy rozdzielić:
        if (lo.eval(m) <= hi.eval(m)) {
            // lo lepsze w środku, hi może być lepsze po prawej
            st[idx].line = lo;
            if (st[idx].r == -1) st[idx].r = newNode();
            add_line_internal(st[idx].r, m+1, r, hi);
        } else {
            // hi lepsze w środku, lo może byc lepsze po lewej
            st[idx].line = hi;
            if (st[idx].l == -1) st[idx].l = newNode();
            add_line_internal(st[idx].l, l, m, lo);
        }
    }

    // PUBLIC: dodaj linię y = k*x + b
    void add(int k, int b) {
        Line nw((ll)k, (ll)b);
        add_line_internal(0, L, R, nw);
    }

    // wewnętrzny query
    ll query_internal(int idx, ll l, ll r, ll x) const {
        if (idx == -1) return (ll)4e18;
        ll cur = st[idx].line.eval(x);
        if (l == r) return cur;
        ll m = (l + r) >> 1;
        if (x <= m) {
            if (st[idx].l == -1) return cur;
            return min(cur, query_internal(st[idx].l, l, m, x));
        } else {
            if (st[idx].r == -1) return cur;
            return min(cur, query_internal(st[idx].r, m+1, r, x));
        }
    }

    // PUBLIC: zapytanie o minimum w punkcie x
    ll query(int x) const {
        if (x < L) x = L;
        if (x > R) x = R;
        return query_internal(0, L, R, x);
    }

    void reset(ll l, ll r) {
        L = l; R = r;
        st.clear();
        st.push_back(Node());
        st[0].line = Line(0, (ll)4e18);
    }
};

vi h;
vi w;
vi pref;
vi dp;

pii obl(int ind) {
    return {h[ind] * h[ind] - pref[ind] + dp[ind], -2*h[ind]};
}

void solve() {
    int n;
    cin >> n;
    h.resize(n);
    w.resize(n);
    f(i, 0, n) cin >> h[i];
    f(i, 0, n) cin >> w[i];
    w[0] = w.back() = 0;
    pref.resize(n);
    pref[0] = w[0];
    f(i, 1, n) pref[i] = pref[i - 1] + w[i];
    dp.resize(n);
    dp[0] = 0;
    cht wsp; //wspolczynniki
    pii p1 = obl(0);
    wsp.add(p1.nd, p1.st);
    f(i, 1, n) {
        dp[i] = h[i] * h[i] + pref[i - 1] + wsp.query(h[i]);
        //cout << "min w h[i]=" << wsp.query(h[i]) << en;
        //cout << "dp[i]=" << dp[i] << en;
        pii p1 = obl(i);
        wsp.add(p1.nd, p1.st);
    }
    cout << dp.back() << en;
}

int32_t main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int q = 1;
    //cin >> q;
    while (q--) {
        solve();
    }
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...