#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = (ll)9e18;
const ll X_MIN = 0;
const ll X_MAX = 1000000000LL; // V_i up to 1e9
struct Line {
ll m, b; // y = m*x + 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; }
};
struct Node {
Line ln;
int l = 0, r = 0;
Node(): ln(), l(0), r(0) {}
};
struct LiChaoRollback {
vector<Node> nodes; // 1-based nodes, nodes[0] unused
vector<int> created; // indices of nodes created (for rollback)
vector<pair<int, Node>> mods; // saved previous node states (idx, oldNode)
LiChaoRollback() { nodes.emplace_back(); } // index 0 unused
int create_node() {
nodes.emplace_back();
int idx = (int)nodes.size() - 1;
created.push_back(idx);
return idx;
}
void backup_node(int idx) {
mods.emplace_back(idx, nodes[idx]);
}
void insert(Line nw, int idx, ll l = X_MIN, ll r = X_MAX) {
if (idx == 0) {
// shouldn't happen: we always create node before recursing
idx = create_node();
}
if (nodes[idx].ln.empty) {
backup_node(idx);
nodes[idx].ln = nw;
return;
}
ll mid = (l + r) >> 1;
// If new is better at mid, swap (store old)
if (nw.eval(mid) < nodes[idx].ln.eval(mid)) {
backup_node(idx);
swap(nodes[idx].ln, nw);
}
if (l == r) return;
if (nw.eval(l) < nodes[idx].ln.eval(l)) {
// go left
if (nodes[idx].l == 0) {
backup_node(idx);
nodes[idx].l = create_node();
}
insert(nw, nodes[idx].l, l, mid);
} else {
// go right
if (nodes[idx].r == 0) {
backup_node(idx);
nodes[idx].r = create_node();
}
insert(nw, nodes[idx].r, mid + 1, r);
}
}
ll query(ll x, int idx, ll l = X_MIN, ll r = X_MAX) const {
if (idx == 0) return INF;
ll res = nodes[idx].ln.eval(x);
if (l == r) return res;
ll mid = (l + r) >> 1;
if (x <= mid) {
if (nodes[idx].l == 0) return res;
return min(res, query(x, nodes[idx].l, l, mid));
} else {
if (nodes[idx].r == 0) return res;
return min(res, query(x, nodes[idx].r, mid + 1, r));
}
}
// wrappers using root index 1
int root() {
if ((int)nodes.size() <= 1) create_node(); // ensure root exists
return 1;
}
pair<int,int> snapshot() const {
return { (int)created.size(), (int)mods.size() };
}
void rollback(pair<int,int> snap) {
int targetCreated = snap.first;
int targetMods = snap.second;
// revert modifications
while ((int)mods.size() > targetMods) {
auto pr = mods.back(); mods.pop_back();
int idx = pr.first;
nodes[idx] = pr.second;
}
// remove newly created nodes
while ((int)created.size() > targetCreated) {
int idx = created.back(); created.pop_back();
// drop last node (must be at position idx)
// nodes vector may be larger; safe to pop_back
nodes.pop_back();
}
// note: parent pointers were restored by reverting mods
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
#if defined(__linux__)
// no-op
#endif
int N;
if (!(cin >> N)) return 0;
vector<vector<pair<int,int>>> g(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});
}
// read harbingers for towns 2..N
vector<ll> S(N+1,0), V(N+1,0);
for (int i = 2; i <= N; ++i) {
cin >> S[i] >> V[i];
}
// compute dist from root (1)
vector<ll> dist(N+1,0);
{
vector<int> st; st.reserve(N);
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;
dist[v] = dist[u] + w;
st.push_back(v);
}
}
}
// dp[1] = 0
vector<ll> dp(N+1, 0);
LiChaoRollback lichao;
// ensure root node index 1 exists
if ((int)lichao.nodes.size() <= 1) lichao.create_node();
int rootIdx = 1;
// insert line for root: m = -dist[1] = 0, b = dp[1] = 0
lichao.insert(Line(-dist[1], dp[1]), rootIdx);
// do DFS from root using recursion with rollback
// recursion depth up to N; acceptable for typical judges
function<void(int,int)> dfs = [&](int u, int p) {
for (auto [v,w]: g[u]) if (v != p) {
// query using current hull (contains ancestors including u)
ll best = lichao.query(V[v], rootIdx);
dp[v] = S[v] + V[v] * dist[v] + best;
// add line for v and recurse
auto snap = lichao.snapshot();
lichao.insert(Line(-dist[v], dp[v]), rootIdx);
dfs(v, u);
lichao.rollback(snap);
}
};
dfs(1, 0);
// 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... |