Submission #1263180

#TimeUsernameProblemLanguageResultExecution timeMemory
1263180amigoo99234Harbingers (CEOI09_harbingers)C++20
60 / 100
1096 ms35548 KiB
#include <bits/stdc++.h>

using namespace std;

//long long MOD = 1e9 + 7;
const long long MOD = 998244353;
// const long long MOD = 100000007 ;


#define fast ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)

#define popCnt(x) (__builtin_popcountll(x))
#define int long long
#define ld long double

#define F  first
#define S  second
#define pi  M_PI
#define all(x) x.begin() , x.end()
#define LL long long
#define SZ(v) (int)(v.size())

int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
const long long OO = LLONG_MAX / 4, N = 3e5 + 5, M = 1e5 + 5, K = 505;

using ll = long long;
const long double NINF = -1e300L;
const long double PINF =  1e300L;

struct Line {
    ll a, b; // y = a*x + b
    Line(ll a = 0, ll b = LLONG_MIN) : a(a), b(b) {}
    inline ll eval(ll x) const { return a * x + b; }
};

struct Op {
    bool added;                       // whether we actually added a line
    vector<Line> removed_lines;       // lines removed from the back while adding
    vector<long double> removed_xs;   // their associated intersection x-values
};

struct RollbackableCHT {
    // lines[i] is active line for interval x >= xs[i]
    vector<Line> lines;
    vector<long double> xs; // xs[0] = -inf
    vector<Op> ops;         // operation log for rollback

    // compute intersection x-coordinate where line l becomes better than r
    long double inter(const Line &l, const Line &r) {
        if (l.a == r.a) {
            // parallel lines: whichever has larger intercept wins everywhere
            return (l.b > r.b) ? PINF : NINF; // if l better => +inf (l dominates to +inf)
        }
        return (long double)(r.b - l.b) / (long double)(l.a - r.a);
    }

    void clear() { lines.clear(); xs.clear(); ops.clear(); }

    // add line with slope strictly greater than previous line's slope
    void add_line(const Line &ln) {
        Op op;
        op.added = true;

        if (lines.empty()) {
            // first line
            lines.push_back(ln);
            xs.push_back(NINF);
            ops.push_back(std::move(op));
            return;
        }

        // equal slope handling: if new line is never better, do nothing.
        if (ln.a == lines.back().a) {
            if (ln.b <= lines.back().b) {
                // new line worse or equal: record no-op so rollback matches calls
                op.added = false;
                ops.push_back(std::move(op));
                return;
            } else {
                // new line strictly better: remove last line (store it)
                op.removed_lines.push_back(lines.back());
                op.removed_xs.push_back(xs.back());
                lines.pop_back();
                xs.pop_back();
                if (lines.empty()) {
                    lines.push_back(ln);
                    xs.push_back(NINF);
                    ops.push_back(std::move(op));
                    return;
                }
            }
        }

        // compute intersection with current back, and pop while intersection
        // is <= previous intersection (meaning back is useless)
        long double x = inter(lines.back(), ln);
        while (!xs.empty() && x <= xs.back()) {
            // remove the last line and record it
            op.removed_lines.push_back(lines.back());
            op.removed_xs.push_back(xs.back());
            lines.pop_back();
            xs.pop_back();
            if (lines.empty()) break;
            x = inter(lines.back(), ln);
        }
        // finally add new line; its valid region starts at x
        lines.push_back(ln);
        xs.push_back(x);
        ops.push_back(std::move(op));
    }

    // query max at arbitrary x
    ll query(ll x) const {
        if (lines.empty()) return LLONG_MIN; // or some sentinel
        // find last index i with xs[i] <= x
        int l = 0, r = (int)xs.size()-1, ans = 0;
        while (l <= r) {
            int m = (l + r) >> 1;
            if (xs[m] <= (long double)x) {
                ans = m;
                l = m + 1;
            } else r = m - 1;
        }
        return lines[ans].eval(x);
    }

    // rollback last add_line() call
    bool rollback() {
        if (ops.empty()) return false;
        Op op = std::move(ops.back());
        ops.pop_back();
        if (!op.added) {
            // no-op add: nothing changed
            return true;
        }
        // remove the line we added
        if (!lines.empty()) {
            lines.pop_back();
            xs.pop_back();
        }
        // restore removed lines in reverse order
        for (int i = (int)op.removed_lines.size() - 1; i >= 0; --i) {
            lines.push_back(op.removed_lines[i]);
            xs.push_back(op.removed_xs[i]);
        }
        return true;
    }
};

RollbackableCHT cht;
int n;
vector<int> v, c;
vector<vector<pair<int, int>>> adj;

vector<int> dp;
void dfs(int node , int p = -1 , int d = 0)
{
    if(p == -1) dp[node] = 0;
    else dp[node] = cht.query(v[node]) + v[node] * d + c[node];

    cht.add_line(Line(-d , dp[node]));

    for(auto [child , len] : adj[node])
    {
        if(child == p)continue;
        dfs(child , node , d + len);
    }
    cht.rollback();
}

signed main() {
    fast;


//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);

    cin >> n;
    dp = v = c = vector<int>(n);
    adj.resize(n);

    for (int i = 0; i < n - 1; ++i) {
        int u, vv, d;
        cin >> u >> vv >> d;
        u--;
        vv--;
        adj[u].emplace_back(vv, d);
        adj[vv].emplace_back(u, d);
    }

    for (int i = 1; i < n; ++i) {
        cin >> c[i] >> v[i];
    }


    dfs(0);

    for(int i = 1 ; i < n ; i++) cout << dp[i] << " ";
    cout<<'\n';



}
#Verdict Execution timeMemoryGrader output
Fetching results...