22// SPDX-FileCopyrightText: 2020-2025 nanoseeds
33#include < algorithm>
44#include < cstdint>
5+ #include < cstdlib>
6+ #include < ctime>
57#include < iostream>
68#include < memory>
79#include < tuple>
@@ -84,13 +86,15 @@ struct ProblemInput {
8486 i32 n;
8587 i32 m;
8688 std::shared_ptr<tree::Graph> graph;
89+ i64 total_weight;
8790};
8891
8992using ProblemOutput = i64 ;
9093
9194ProblemInput read_input ();
9295ProblemOutput solve (const ProblemInput &in);
9396void write_output (const ProblemOutput &out);
97+ static bool can_form_paths (const ProblemInput &in, const i64 limit);
9498
9599int main () {
96100 const auto in = read_input ();
@@ -106,21 +110,110 @@ ProblemInput read_input() {
106110 int32_t v;
107111 int64_t w;
108112 in.graph = std::make_shared<tree::Graph>(in.n , static_cast <int32_t >((in.n - 1 ) * 2 ));
113+ in.total_weight = 0 ;
109114 for (i32 i = 0 ; i < in.n - 1 ; ++i) {
110115 std::cin >> u >> v >> w;
111- in.graph ->add_undirected_edge (u,v,w);
116+ in.graph ->add_undirected_edge (u, v, w);
117+ in.total_weight += w;
112118 }
113119 return in;
114120}
115121
116122
117123ProblemOutput solve (const ProblemInput &in) {
124+ i64 left = 0 ;
125+ i64 right = in.total_weight ;
126+ i64 answer = 0 ;
127+ while (left <= right) {
128+ const auto mid = (left + right) >> 1 ;
129+ if (can_form_paths (in, mid)) {
130+ answer = mid;
131+ left = mid + 1 ;
132+ } else {
133+ right = mid - 1 ;
134+ }
135+ }
136+ return answer;
118137}
119138
120139void write_output (const ProblemOutput &out) {
121140 std::cout << out << end;
122141}
123142
143+ static bool can_form_paths (const ProblemInput &in, const i64 limit) {
144+ if (limit <= 0 ) return true ;
145+ const auto &graph = *in.graph ;
146+ const auto n = in.n ;
147+ std::vector<int32_t > parent (static_cast <size_t >(n + 1 ), 0 );
148+ std::vector<int32_t > order;
149+ order.reserve (static_cast <size_t >(n));
150+ std::vector<int32_t > stack;
151+ stack.reserve (static_cast <size_t >(n));
152+ stack.push_back (1 );
153+ parent[1 ] = 0 ;
154+ while (!stack.empty ()) {
155+ const auto u = stack.back ();
156+ stack.pop_back ();
157+ order.push_back (u);
158+ for (auto ei = graph.head [static_cast <size_t >(u)]; ei != -1 ; ei = graph.edges [static_cast <size_t >(ei)].next ) {
159+ const auto &edge = graph.edges [static_cast <size_t >(ei)];
160+ if (edge.to == parent[static_cast <size_t >(u)]) continue ;
161+ parent[static_cast <size_t >(edge.to )] = u;
162+ stack.push_back (edge.to );
163+ }
164+ }
165+ std::vector<i64 > dp (static_cast <size_t >(n + 1 ), 0 );
166+ int32_t formed = 0 ;
167+ std::vector<i64 > lengths;
168+ std::vector<bool > used;
169+
170+ for (auto it = order.rbegin (); it != order.rend (); ++it) {
171+ const auto u = *it;
172+ lengths.clear ();
173+ for (auto ei = graph.head [static_cast <size_t >(u)]; ei != -1 ; ei = graph.edges [static_cast <size_t >(ei)].next ) {
174+ const auto &edge = graph.edges [static_cast <size_t >(ei)];
175+ if (parent[static_cast <size_t >(u)] == edge.to ) continue ;
176+ lengths.push_back (dp[static_cast <size_t >(edge.to )] + edge.weight );
177+ }
178+
179+ std::sort (lengths.rbegin (), lengths.rend ());
180+
181+ used.assign (lengths.size (), false );
182+ int32_t l = 0 ;
183+ int32_t r = static_cast <int32_t >(lengths.size ()) - 1 ;
184+
185+ while (l < r) {
186+ if (used[l]) {
187+ l++;
188+ continue ;
189+ }
190+ while (l < r && (used[r] || lengths[l] + lengths[r] < limit)) {
191+ r--;
192+ }
193+ if (l < r) {
194+ formed++;
195+ used[l] = used[r] = true ;
196+ l++;
197+ r--;
198+ }
199+ }
200+
201+ i64 carry = 0 ;
202+ for (size_t i = 0 ; i < lengths.size (); ++i) {
203+ if (!used[i]) {
204+ if (lengths[i] >= limit) {
205+ formed++;
206+ used[i] = true ;
207+ } else {
208+ carry = std::max (carry, lengths[i]);
209+ }
210+ }
211+ }
212+ dp[static_cast <size_t >(u)] = carry;
213+ }
214+ return formed >= in.m ;
215+ }
216+
124217static const auto faster_streams = [] {
125218 srand (time (nullptr ));
126219 // use time to init the random seed
0 commit comments