1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
using int64 = long long;
struct Line {
int64 m, b; // y = m*x + b
};
struct Node {
Line ln; // best line on this segment
int left, right; // children indices
};
static const int64 X_MIN = 0;
static const int64 X_MAX = 1000000000LL; // V_i in [1..1e9]
static const int64 INF = (1LL << 62);
inline int64 eval(const Line &ln, int64 x) {
return (int64)((__int128)ln.m * x + ln.b);
}
vector<Node> lichao; // 0 is null
inline int clone_node(int idx) {
if (idx == 0) {
lichao.push_back(Node{{0, INF}, 0, 0});
return (int)lichao.size() - 1;
}
lichao.push_back(lichao[idx]);
return (int)lichao.size() - 1;
}
int insert_line(int idx, int64 l, int64 r, Line nw) {
int cur = clone_node(idx);
Line lo = lichao[cur].ln, hi = nw;
int64 mid = (l + r) >> 1;
if (eval(lo, mid) > eval(hi, mid)) swap(lo, hi);
lichao[cur].ln = lo;
if (l == r) return cur;
if (eval(lo, l) > eval(hi, l)) {
lichao[cur].left = insert_line(lichao[cur].left, l, mid, hi);
} else if (eval(lo, r) > eval(hi, r)) {
lichao[cur].right = insert_line(lichao[cur].right, mid + 1, r, hi);
}
return cur;
}
int64 query_min(int idx, int64 l, int64 r, int64 x) {
if (idx == 0) return INF;
int64 res = eval(lichao[idx].ln, x);
if (l == r) return res;
int64 mid = (l + r) >> 1;
if (x <= mid) return min(res, query_min(lichao[idx].left, l, mid, x));
return min(res, query_min(lichao[idx].right, mid + 1, r, x));
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
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});
}
vector<int64> S(N + 1, 0), V(N + 1, 0);
for (int i = 2; i <= N; ++i) {
int64 s, v;
cin >> s >> v;
S[i] = s; V[i] = v;
}
// Compute distances from root (1)
vector<int64> dist(N + 1, 0);
vector<int> par(N + 1, 0);
par[1] = -1;
vector<int> stk;
stk.push_back(1);
while (!stk.empty()) {
int u = stk.back(); stk.pop_back();
for (auto [v, w] : g[u]) if (v != par[u]) {
par[v] = u;
dist[v] = dist[u] + w;
stk.push_back(v);
}
}
lichao.reserve(N * 32 + 5);
lichao.push_back(Node{{0, INF}, 0, 0}); // index 0: null
vector<int64> dp(N + 1, 0);
struct Frame { int u, p, root; };
vector<Frame> dfs;
dfs.push_back({1, 0, 0}); // start with empty structure
while (!dfs.empty()) {
auto [u, p, root] = dfs.back();
dfs.pop_back();
int nextRoot = root;
if (u == 1) {
dp[1] = 0;
// Insert line for root: m = -D[1] = 0, b = dp[1] = 0
nextRoot = insert_line(nextRoot, X_MIN, X_MAX, Line{0, 0});
} else {
int64 best = query_min(root, X_MIN, X_MAX, V[u]); // min_x (dp[x] - V[u]*D[x])
dp[u] = S[u] + (int64)((__int128)V[u] * dist[u]) + best;
// Make current node available to descendants: y = -D[u] * x + dp[u]
nextRoot = insert_line(root, X_MIN, X_MAX, Line{-dist[u], dp[u]});
}
for (auto [v, w] : g[u]) if (v != p) {
dfs.push_back({v, u, nextRoot});
}
}
for (int i = 2; i <= N; ++i) {
if (i > 2) cout << ' ';
cout << dp[i];
}
cout << '\n';
return 0;
}
|