#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = (ll)9e18;
struct Line {
ll m, b;
bool empty;
Line(): m(0), b(0), empty(true) {}
Line(ll _m, ll _b): m(_m), b(_b), empty(false) {}
ll eval(ll x) const { return empty ? INF : m * x + b; }
};
int N;
vector<vector<pair<int,int>>> g;
vector<ll> S, V, distv, dp;
vector<ll> xs; // compressed unique V values
vector<Line> seg; // segment tree of lines (size 4*M)
vector<pair<int, Line>> mods; // stack of modifications for rollback
// backup seg[idx] before overwriting
void save_mod(int idx) {
mods.emplace_back(idx, seg[idx]);
}
// insert line into node id covering [l..r] (indices into xs)
void insert_line(Line nw, int id, int l, int r) {
int mid = (l + r) >> 1;
ll xl = xs[l], xm = xs[mid], xr = xs[r];
if (seg[id].empty) {
save_mod(id);
seg[id] = nw;
return;
}
// ensure seg[id] is better at xm
if (nw.eval(xm) < seg[id].eval(xm)) {
save_mod(id);
swap(seg[id], nw);
}
if (l == r) return;
// If new line is better at left endpoint, go left
if (nw.eval(xl) < seg[id].eval(xl)) {
insert_line(nw, id<<1, l, mid);
}
// else if new line is better at right endpoint, go right
else if (nw.eval(xr) < seg[id].eval(xr)) {
insert_line(nw, id<<1|1, mid+1, r);
}
// else nowhere dominated on this segment
}
ll query_x(ll xq, int id, int l, int r) {
if (id >= (int)seg.size()) return INF;
ll res = seg[id].eval(xq);
if (l == r) return res;
int mid = (l + r) >> 1;
if (xq <= xs[mid]) return min(res, query_x(xq, id<<1, l, mid));
else return min(res, query_x(xq, id<<1|1, mid+1, r));
}
pair<int,int> snapshot() {
return { (int)mods.size(), 0 }; // second unused but kept similar to earlier API
}
void rollback(pair<int,int> snap) {
int target = snap.first;
while ((int)mods.size() > target) {
auto pr = mods.back(); mods.pop_back();
seg[pr.first] = pr.second;
}
}
void dfs(int u, int p, int M) {
for (auto [v, w] : g[u]) if (v != p) {
// query current hull at V[v]
ll best = query_x(V[v], 1, 0, M-1);
dp[v] = S[v] + V[v] * distv[v] + best;
// insert line for v: y(x) = dp[v] + (-dist[v]) * x
auto snap = snapshot();
insert_line(Line(-distv[v], dp[v]), 1, 0, M-1);
dfs(v, u, M);
rollback(snap);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
if (!(cin >> N)) return 0;
g.assign(N+1, {});
for (int i = 0; i < N-1; ++i) {
int u,v,d; cin >> u >> v >> d;
g[u].push_back({v,d});
g[v].push_back({u,d});
}
S.assign(N+1, 0);
V.assign(N+1, 0);
for (int i = 2; i <= N; ++i) cin >> S[i] >> V[i];
// compute dist from root (1)
distv.assign(N+1, 0);
{
vector<int> st; st.push_back(1);
vector<int> parent(N+1, -1);
parent[1] = 0;
while (!st.empty()) {
int u = st.back(); st.pop_back();
for (auto [v,w]: g[u]) if (v != parent[u]) {
parent[v] = u;
distv[v] = distv[u] + w;
st.push_back(v);
}
}
}
// compress V values (we only need to query at these)
xs.clear();
for (int i = 2; i <= N; ++i) xs.push_back(V[i]);
sort(xs.begin(), xs.end());
xs.erase(unique(xs.begin(), xs.end()), xs.end());
int M = (int)xs.size();
if (M == 0) return 0; // no queries, but N>=3 so shouldn't happen
// prepare segment tree arrays; size 4*M is safe
seg.assign(4*M + 5, Line());
mods.clear();
dp.assign(N+1, 0);
// root line: dp[1] = 0, dist[1] = 0 => y = 0
// insert root line before starting DFS
insert_line(Line(-distv[1], dp[1]), 1, 0, M-1);
dfs(1, 0, M);
// output dp[2..N]
for (int i = 2; i <= N; ++i) {
if (i > 2) cout << ' ';
cout << dp[i];
}
cout << '\n';
return 0;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |