Submission #1278468

#TimeUsernameProblemLanguageResultExecution timeMemory
1278468Ice_manHarbingers (CEOI09_harbingers)C++20
50 / 100
71 ms26700 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<ll,ll>;
const ll LINF = (ll)4e18;

struct CHT {
    // Lines in the hull are stored in order of decreasing slope for min query
    vector<pll> hull;

    // Intersection check with integer arithmetic to avoid precision issues
    bool bad(const pll &l1, const pll &l2, const pll &l3) {
        // return true if l2 is useless
        // cross(l1,l2) >= cross(l2,l3)
        return (l2.second - l1.second) * (l1.first - l3.first) >= (l3.second - l1.second) * (l1.first - l2.first);
    }

    void add_line(pll ln) {
        while(hull.size() >= 2 && bad(hull[hull.size()-2], hull.back(), ln))
            hull.pop_back();
        hull.push_back(ln);
    }

    ll query(ll x) {
        if(hull.empty()) return LINF;
        int l = 0, r = hull.size()-1;
        while(l < r) {
            int m = (l+r)/2;
            ll val1 = hull[m].first * x + hull[m].second;
            ll val2 = hull[m+1].first * x + hull[m+1].second;
            if(val1 > val2) l = m+1;
            else r = m;
        }
        return hull[l].first * x + hull[l].second;
    }
};

const int MAXN = 200005;
int n;
vector<pair<int,int>> g[MAXN];
ll waitt[MAXN], speed[MAXN], dp[MAXN], dista[MAXN];
int parent0[MAXN], sz[MAXN], heavy[MAXN], head[MAXN], depth0[MAXN];
vector<int> nodes_by_depth[MAXN];
CHT cht[MAXN]; // one CHT per chain

void dfs_sz(int u, int p){
    parent0[u] = p;
    sz[u] = 1;
    heavy[u] = -1;
    nodes_by_depth[depth0[u]].push_back(u);
    for(auto &e : g[u]){
        int v = e.first, w = e.second;
        if(v==p) continue;
        depth0[v] = depth0[u]+1;
        dista[v] = dista[u]+w;
        dfs_sz(v,u);
        sz[u] += sz[v];
        if(heavy[u]==-1 || sz[v]>sz[heavy[u]]) heavy[u]=v;
    }
}

void dfs_hld(int u, int h){
    head[u] = h;
    if(heavy[u]!=-1) dfs_hld(heavy[u],h);
    for(auto &e : g[u]){
        int v = e.first;
        if(v==parent0[u] || v==heavy[u]) continue;
        dfs_hld(v,v);
    }
}

// Query from node u to root along chains
ll query(int u){
    ll res = LINF;
    while(u){
        int h = head[u];
        res = min(res, cht[h].query(speed[u]));
        u = parent0[h];
    }
    return res;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;
    for(int i=1;i<=n;++i) g[i].clear();
    for(int i=1;i<=n-1;++i){
        int x,y,z; cin >> x >> y >> z;
        g[x].push_back({y,z});
        g[y].push_back({x,z});
    }
    for(int i=2;i<=n;++i) cin >> waitt[i] >> speed[i];

    dista[1] = 0;
    depth0[1] = 0;
    parent0[1] = 0;
    dfs_sz(1,0);
    dfs_hld(1,1);

    dp[1] = 0;
    cht[head[1]].add_line({-dista[1],dp[1]});

    // process nodes level by level
    for(int d=1;d<=n;++d){
        if(nodes_by_depth[d].empty()) continue;
        // compute dp[node]
        for(int node : nodes_by_depth[d]){
            ll best = query(node);
            ll val = waitt[node] + speed[node]*dista[node];
            if(best != LINF) val = min(val, best + speed[node]*dista[node] + waitt[node]);
            dp[node] = val;
        }
        // add lines to their chains
        for(int node : nodes_by_depth[d]){
            cht[head[node]].add_line({-dista[node], dp[node]});
        }
    }

    for(int i=2;i<=n;++i){
        cout << dp[i] << (i<n?' ':'\n');
    }
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...