@@ -15,8 +15,14 @@ using namespace std;
1515using ll = pair<long , long >;
1616using lll = tuple<long , long , long >;
1717using vvll = vector<vector<ll>>;
18+ using vl = vector<long >;
1819using vvl = vector<vector<long >>;
1920
21+ vvll tree;
22+ vl tip, depth, parent, parent_weight;
23+ vvl pred;
24+ vector<long long > subtree_loop_opt, supertree_loop_opt, supertree_root_opt;
25+
2026long long positive_part (long long x) { return max (0LL , x); }
2127
2228// Διασχίζει το δέντρο `tree` ξεκινώντας από την κορυφή `u` και υπολογίζει
@@ -29,109 +35,93 @@ long long positive_part(long long x) { return max(0LL, x); }
2935// της ρίζας είναι 0.
3036// `parent[u]`: Ο γονέας του `u`.
3137// `parent_weight[u]`: Κόστος του δρόμου που συνδέει τον `u` με τον γονέα του.
32- void compute_auxiliary (const vvll& tree, int u, vector<long >& depth, vector<long >& parent, vector<long >& parent_weight) {
33- const long n = tree.size ();
34- assert (depth.size () >= n);
35- assert (parent.size () >= n);
36- assert (parent_weight.size () >= n);
37- assert (0 <= u && u < n);
38-
38+ void compute_auxiliary (int u) {
3939 for (auto [v, w]: tree[u]) {
4040 if (v == parent[u]) continue ;
41- assert (0 <= v && v < n);
42-
4341 parent[v] = u;
4442 parent_weight[v] = w;
4543 depth[v] = depth[u] + 1 ;
4644
47- compute_auxiliary (tree, v, depth, parent, parent_weight );
45+ compute_auxiliary (v );
4846 }
4947}
5048
5149// Διασχίζει το δέντρο `tree` και υπολογίζει αναδρομικά τις τιμές
52- // `subtree_loop_opt` για την κορυφή `u` κι όλους τους απογόνους της. Η τιμή της
53- // `parent` είναι ο γονέας της `u`.
50+ // `subtree_loop_opt` για την κορυφή `u` κι όλους τους απογόνους της.
5451//
5552// `subtree_loop_opt[u]`: Το κέρδος της βέλτιστης διαδρομής η οποία ξεκινάει
5653// και καταλήγει πάλι πίσω στο `u`, παραμένοντας στο υποδέντρο που ορίζει
5754// η κορυφή `u`. Mε άλλα λόγια, η διαδρομή απαγορεύεται να διασχίσει
5855// τον δρόμο `(u, parent)`.
59- void compute_subtree_loop_opt (vector< long long > &subtree_loop_opt, const vvll &tree, const vector< long > &tip, long u, long parent ) {
56+ void compute_subtree_loop_opt (long u ) {
6057 subtree_loop_opt[u] = tip[u];
6158
6259 for (auto [v, w]: tree[u]) {
63- if (v == parent) continue ;
64- compute_subtree_loop_opt (subtree_loop_opt, tree, tip, v, u );
60+ if (v == parent[u] ) continue ;
61+ compute_subtree_loop_opt (v );
6562 subtree_loop_opt[u] += positive_part (subtree_loop_opt[v] - 2 *w);
6663 }
6764}
6865
6966// Διασχίζει το δέντρο `tree` και υπολογίζει αναδρομικά τις τιμές
7067// `subtree_root_opt` για την κορυφή `u` κι όλους τους απογόνους της,
7168// χρησιμοποιώντας τις τιμές `subtree_loop_opt` που υπολογίσαμε ήδη στην
72- // προηγούμενη διάσχιση. Η τιμή της `parent` είναι ο γονέας της `u`.
69+ // προηγούμενη διάσχιση.
7370//
7471// `supertree_root_opt[u]`: Το κέρδος της βέλτιστης διαδρομής η οποία ξεκινάει
7572// από την κορυφή `u`, καταλήγει στη ρίζα του δέντρου και
7673// μένει πάντα ΕΚΤΟΣ του υποδέντρου που ορίζει η `u`. Το φιλοδώρημα της κορυφής
7774// `u` ΔΕΝ προσμετράται.
78- void compute_supertree_root_opt (vector<long long >& supertree_root_opt, const vector<long long >& subtree_loop_opt, const vvll& tree, long u, long parent, long w) {
79- assert (0 <= u && u < tree.size ());
80- assert (-1 <= parent && parent < (long )tree.size ());
81-
75+ void compute_supertree_root_opt (long u) {
8276 supertree_root_opt[u] = 0 ;
8377
84- if (parent != -1 )
85- supertree_root_opt[u] = subtree_loop_opt[parent] + supertree_root_opt[parent] - positive_part (subtree_loop_opt[u] - 2 *w) - w;
78+ if (parent[u] != -1 )
79+ supertree_root_opt[u] =
80+ subtree_loop_opt[parent[u]] + supertree_root_opt[parent[u]]
81+ - positive_part (subtree_loop_opt[u] - 2 *parent_weight[u]) - parent_weight[u];
8682
8783 for (auto [v, w]: tree[u])
88- if (v != parent)
89- compute_supertree_root_opt (supertree_root_opt, subtree_loop_opt, tree, v, u, w );
84+ if (v != parent[u] )
85+ compute_supertree_root_opt (v );
9086}
9187
9288// Διασχίζει το δέντρο `tree` και υπολογίζει αναδρομικά τις τιμές
9389// `subtree_loop_opt` για την κορυφή `u` κι όλους τους απογόνους της,
9490// χρησιμοποιώντας τις τιμές `subtree_loop_opt` που υπολογίσαμε ήδη στην
95- // προηγούμενη διάσχιση. Η τιμή της `parent` είναι ο γονέας της `u`.
91+ // προηγούμενη διάσχιση.
9692//
9793// supertree_loop_opt[u] = κέρδος της βέλτιστης διαδρομής η οποία ξεκινάει αλλά
9894// ΚΑΙ καταλήγει στην κορυφή `u`, και μένει πάντα ΕΚΤΟΣ του υποδέντρου που
9995// ορίζει η `u`. Το φιλοδώρημα της κορυφής `u` ΔΕΝ προσμετράται.
100- void compute_supertree_loop_opt (vector<long long >& supertree_loop_opt, const vector<long long >& subtree_loop_opt, const vvll& tree, int u, int parent, int w) {
101- assert (0 <= u && u < tree.size ());
102- assert (-1 <= parent && parent < (long )tree.size ());
103-
96+ void compute_supertree_loop_opt (int u) {
10497 supertree_loop_opt[u] = 0 ;
10598
106- if (parent != -1 )
107- supertree_loop_opt[u] = positive_part (subtree_loop_opt[parent] + supertree_loop_opt[parent] - positive_part (subtree_loop_opt[u] - 2 *w) - 2 *w);
99+ if (parent[u] != -1 )
100+ supertree_loop_opt[u] =
101+ positive_part (subtree_loop_opt[parent[u]] + supertree_loop_opt[parent[u]]
102+ - positive_part (subtree_loop_opt[u] - 2 *parent_weight[u]) - 2 *parent_weight[u]);
108103
109104 for (auto [v, w]: tree[u])
110- if (v != parent)
111- compute_supertree_loop_opt (supertree_loop_opt, subtree_loop_opt, tree, v, u, w );
105+ if (v != parent[u] )
106+ compute_supertree_loop_opt (v );
112107}
113108
114- // Υπολογίζει τον πίνακα `pred` έτσι ώστε:
109+ // Υπολογίζει τον πίνακα `pred` έτσι ώστε για κάθε 0 <= h <= H, 0 <= u < N :
115110// `pred[h][u] == v` αν και μόνο αν ο `v` είναι ο `2^h`-πρόγονος του `u`.
116111// Για παράδειγμα `pred[0][u] == parent[u]` γιατί ο γονέας του $u$
117112// είναι ο `2^0 = 1`-ος πρόγονός του.
118- // Ο πίνακας εισόδου `parent` θα πρέπει για κάθε κορυφή να περιέχει
119- // τον γονέα της, εκτός από την ρίζα `r` για την οποία θα πρέπει να ισχύει
120- // `parent[r] == r`.
121- void compute_pred (const vector<long > &parent, vvl &pred)
122- {
123- const long H = pred.size () - 1 ;
113+ // O caller θα πρέπει να έχει ήδη υπολογίσει τον πίνακα parent
114+ // (δες `compute_auxiliary`) έτσι ώστε η τιμή `parent[u]` να είναι
115+ // ο γονέας της `u`, εκτός από την ρίζα `r` για την οποία `r == parent[r]`.
116+ void compute_pred (long H) {
124117 const long n = parent.size ();
125118
126119 for (long u = 0 ; u < n; ++u)
127120 pred[0 ][u] = parent[u];
128121
129122 for (long h = 1 ; h <= H; ++h)
130123 for (long u = 0 ; u < n; ++u)
131- {
132- assert (0 <= pred[h - 1 ][u] && pred[h - 1 ][u] < n);
133124 pred[h][u] = pred[h - 1 ][pred[h - 1 ][u]];
134- }
135125}
136126
137127// Υπολογίζει τρεις τιμές `(z, a, b)` όπου `z` είναι ο Ελάχιστος Κοινός Πρόγονος
@@ -140,44 +130,38 @@ void compute_pred(const vector<long> &parent, vvl &pred)
140130// αντίστοιχα `b` είναι η μοναδική κορυφή στο μονοπάτι από `z` προς `v` τέτοια
141131// ώστε `parent[v] == z` (ή `b == -1` αν τέτοια κορυφή δεν υπάρχει).
142132//
143- // Η συνάρτηση λαμβάνει ως είσοδο και τον πίνακα `pred` που υπολόγισε νωρίτερα η
133+ // Η συνάρτηση χρησιμοποιεί τον πίνακα `pred` που υπολόγισε νωρίτερα η
144134// συνάρτηση `compute_pred` καθώς και τον πίνακα `depth` που υπολόγισε νωρίτερα
145135// η συνάρτηση `compute_auxiliary`.
146- lll lca (const vector<vector< long >> &pred, const vector< long > &depth, long u, long v) {
136+ lll lca (long u, long v) {
147137 const long H = pred.size () - 1 ;
148138
149139 if (u == v)
150140 return {u, -1 , -1 };
151141
152142 if (depth[u] < depth[v]) {
153- auto [w, i, j] = lca (pred, depth, v, u);
143+ auto [w, i, j] = lca (v, u);
154144 return {w, j, i};
155145 }
156146
157147 if (depth[u] != depth[v]) {
158148 for (long h = H; h >= 0 ; h--)
159149 if (depth[ pred[h][u] ] > depth[v])
160150 u = pred[h][u];
161-
162- assert (depth[pred[0 ][u]] == depth[v]);
163151
164152 if (pred[0 ][u] == v)
165153 return { v, u, -1 };
166154
167155 u =pred[0 ][u];
168156 }
169157
170- assert (depth[u] == depth[v]);
171- assert (u != v);
172-
173158 for (long h = H; h >= 0 ; --h) {
174159 if (pred[h][u] != pred[h][v]) {
175160 u = pred[h][u];
176161 v = pred[h][v];
177162 }
178163 }
179164
180- assert (pred[0 ][u] == pred[0 ][v]);
181165 return { pred[0 ][u], u, v };
182166}
183167
@@ -188,19 +172,17 @@ int main() {
188172 long n, q;
189173 scanf (" %li%li" , &n, &q);
190174
191- vector< long > tip (n);
175+ tip. resize (n);
192176 for (long i = 0 ; i < n; ++i)
193177 scanf (" %li" , &tip[i]);
194178
195179 // Αναπαράσταση του δέντρου με adjacency list:
196180 // To `tree[u]` περιέχει ένα vector με pairs `(v, w)` για κάθε κορυφή `v` που
197181 // συνδέεται με τη `u` με κόστός `w`.
198- vvll tree (n);
182+ tree. resize (n);
199183 for (long i = 0 ; i < n-1 ; ++i) {
200184 long u, v, w;
201185 scanf (" %li%li%li" , &u, &v, &w);
202- assert (1 <= u && u <= n);
203- assert (1 <= v && v <= n);
204186
205187 tree[u-1 ].push_back ({v-1 , w});
206188 tree[v-1 ].push_back ({u-1 , w});
@@ -209,8 +191,10 @@ int main() {
209191 // Αρχικοποιώντας `depth[0] = 0`, `parent[0] = 0` θέτουμε την κορυφή
210192 // 0 ως ρίζα του δέντρου. Η συνάρτηση `compute_auxiliary` συμπληρώνει
211193 // τις τιμές και για τους υπόλοιπους κόμβους.
212- vector<long > depth (n, 0 ), parent (n, 0 ), parent_weight (n, 0 );
213- compute_auxiliary (tree, 0 , depth, parent, parent_weight);
194+ depth.resize (n, 0 );
195+ parent.resize (n, 0 );
196+ parent_weight.resize (n, 0 );
197+ compute_auxiliary (0 );
214198
215199 // Θα χρειαστούμε το μέγιστο βάθος ώστε να υπολογίσουμε τις διαστάσεις
216200 // πίνακα `pred` παρακάτω.
@@ -222,13 +206,15 @@ int main() {
222206 // Το δέντρο έχει ύψος `max_depth` επομένως θα χρειαστούμε τους
223207 // απογόνους (predecessors) το πολύ μέχρι `max_depth <= 2^H` επίπεδα παραπάνω.
224208 const long H = long (ceil (log2 (max_depth)));
225- vector<vector< long >> pred (H+1 , vector<long >(n, 0 ));
226- compute_pred (parent, pred );
209+ pred. resize (H+1 , vector<long >(n, 0 ));
210+ compute_pred (H );
227211
228- vector<long long > subtree_loop_opt (n), supertree_root_opt (n), supertree_loop_opt (n);
229- compute_subtree_loop_opt (subtree_loop_opt, tree, tip, 0 , -1 );
230- compute_supertree_root_opt (supertree_root_opt, subtree_loop_opt, tree, 0 , -1 , -1 );
231- compute_supertree_loop_opt (supertree_loop_opt, subtree_loop_opt, tree, 0 , -1 , -1 );
212+ subtree_loop_opt.resize (n);
213+ supertree_loop_opt.resize (n);
214+ supertree_root_opt.resize (n);
215+ compute_subtree_loop_opt (0 );
216+ compute_supertree_root_opt (0 );
217+ compute_supertree_loop_opt (0 );
232218
233219 for (long i = 0 ; i < q; ++i) {
234220 long L, R;
@@ -241,7 +227,7 @@ int main() {
241227 continue ;
242228 }
243229
244- auto [z, u, v] = lca (pred, depth, L, R);
230+ auto [z, u, v] = lca (L, R);
245231 assert (u != -1 || v != -1 );
246232
247233 long long sol = 0 ;
0 commit comments