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;
}
  |