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
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
static const int INF = 1e9;
int N, K;
vector<vector<pair<int,int>>> graphEdges;
vector<int> subtreeSize;
vector<char> isBlocked;
vector<int> bestDist; // bestDist[distance] = minimal edges to achieve this distance (from previous children)
vector<int> touchedDistances; // indices in bestDist that we set during current centroid processing
int answerMinEdges = INF;
int computeSubtreeSize(int node, int parent) {
subtreeSize[node] = 1;
for (const auto &edge : graphEdges[node]) {
int next = edge.first;
if (next == parent || isBlocked[next]) continue;
subtreeSize[node] += computeSubtreeSize(next, node);
}
return subtreeSize[node];
}
int findCentroid(int node, int parent, int totalSize) {
for (const auto &edge : graphEdges[node]) {
int next = edge.first;
if (next == parent || isBlocked[next]) continue;
if (subtreeSize[next] * 2 > totalSize) {
return findCentroid(next, node, totalSize);
}
}
return node;
}
void collectDistances(int node, int parent, int dist, int edgesUsed, vector<pair<int,int>> &buffer) {
if (dist > K) return;
buffer.emplace_back(dist, edgesUsed);
for (const auto &edge : graphEdges[node]) {
int next = edge.first, w = edge.second;
if (next == parent || isBlocked[next]) continue;
int nd = dist + w;
if (nd > K) continue; // prune
collectDistances(next, node, nd, edgesUsed + 1, buffer);
}
}
void decompose(int entry) {
int total = computeSubtreeSize(entry, -1);
int centroid = findCentroid(entry, -1, total);
isBlocked[centroid] = 1;
// Initialize bestDist for this centroid (distance 0 with 0 edges at the centroid itself)
if (bestDist[0] == INF) touchedDistances.push_back(0);
bestDist[0] = 0;
// Process each child subtree: query against bestDist (paths via centroid), then insert this subtree's distances
for (const auto &edge : graphEdges[centroid]) {
int child = edge.first, w = edge.second;
if (isBlocked[child]) continue;
vector<pair<int,int>> collected;
if (w <= K) collectDistances(child, centroid, w, 1, collected);
for (const auto &p : collected) {
int d = p.first, e = p.second;
int need = K - d;
if (need < 0) continue;
if (bestDist[need] != INF) {
answerMinEdges = min(answerMinEdges, bestDist[need] + e);
}
}
for (const auto &p : collected) {
int d = p.first, e = p.second;
if (bestDist[d] == INF) touchedDistances.push_back(d);
if (bestDist[d] > e) bestDist[d] = e;
}
}
// Clear bestDist updates for this centroid
for (int d : touchedDistances) bestDist[d] = INF;
touchedDistances.clear();
// Recurse on remaining components
for (const auto &edge : graphEdges[centroid]) {
int child = edge.first;
if (!isBlocked[child]) decompose(child);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
if (!(cin >> N >> K)) return 0;
graphEdges.assign(N, {});
for (int i = 0; i < N - 1; i++) {
int a, b, w;
cin >> a >> b >> w;
graphEdges[a].push_back({b, w});
graphEdges[b].push_back({a, w});
}
subtreeSize.assign(N, 0);
isBlocked.assign(N, 0);
bestDist.assign(K + 1, INF);
touchedDistances.reserve(1 << 16);
decompose(0);
cout << (answerMinEdges == INF ? -1 : answerMinEdges) << '\n';
return 0;
}
|