← Home
/*
Author: Nguyen Chi Thanh - High School for the Gifted - VNU.HCM (i2528)
*/
#include <bits/stdc++.h>
using namespace std;
 
/* START OF TEMPALTE */
 
// #define int long long
#define ll long long
#define ull unsigned long long
#define ld long double
#define pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define __builtin_popcount __builtin_popcountll
#define all(x) (x).begin(), (x).end()
#define BIT(x, i) (((x) >> (i)) & 1)
#define MASK(x) (1ll << (x))
#define SZ(a) ((int32_t)a.size())
 
#define debug(a, l, r) {for (int _i = (l); _i <= (r); ++_i) cout << (a)[_i] << ' '; cout << '\n';}
 
template<class X, class Y>
bool minimize(X &x, const Y &y) {
    if (x > y) {
        x = y;
        return true;
    } else return false;
}
 
template<class X, class Y>
bool maximize(X &x, const Y &y) {
    if (x < y) {
        x = y;
        return true;
    } else return false;
}
 
/* END OF TEMPALTE */
 
const int INF = 1e9 + 5;
 
struct Node {
    int mxval, u;
};
 
Node operator + (Node x, Node y) {
    if (x.mxval > y.mxval) return x;
    return y;
}
 
// SegTree copied from atcoder library
int ceil_pow2(int n) {
    int x = 0;
    while ((1U << x) < (unsigned int)(n)) x++;
    return x;
}
 
template<
    class T,  // data type for nodes
    T (*op) (T, T),  // operator to combine 2 nodes
    T (*e)() // identity element
>
struct SegTree {
    SegTree() : SegTree(0) {}
    explicit SegTree(int n) : SegTree(vector<T> (n, e())) {}
    explicit SegTree(const vector<T>& v) : _n((int) v.size()) {
        log = ceil_pow2(_n);
        size = 1<<log;
        d = vector<T> (2*size, e());
 
        for (int i = 0; i < _n; i++) d[size+i] = v[i];
        for (int i = size - 1; i >= 1; i--) {
            update(i);
        }
    }
 
    void reset() {
        fill(all(d),e());
    }
 
    // 0 <= p < n
    void set(int p, T x) {
        assert(0 <= p && p < _n);
        p += size;
        d[p] = d[p] + x;
        for (int i = 1; i <= log; i++) update(p >> i);
    }
 
    // 0 <= p < n
    T get(int p) const {
        assert(0 <= p && p < _n);
        return d[p + size];
    }
 
    // Get product in range [l, r-1]
    // 0 <= l <= r <= n
    // For empty segment (l == r) -> return e()
    T prod(int l, int r) const {
        assert(0 <= l && l <= r && r <= _n);
        T sml = e(), smr = e();
        l += size;
        r += size;
        while (l < r) {
            if (l & 1) sml = op(sml, d[l++]);
            if (r & 1) smr = op(d[--r], smr);
            l >>= 1;
            r >>= 1;
        }
        return op(sml, smr);
    }
 
    T all_prod() const {
        return d[1];
    }
 
    // Binary search on SegTree to find largest r:
    //    f(op(a[l] .. a[r-1])) = true   (assuming empty array is always true)
    //    f(op(a[l] .. a[r])) = false    (assuming op(..., a[n]), which is out of bound, is always false)
    template <bool (*f)(T)> int max_right(int l) const {
        return max_right(l, [](T x) { return f(x); });
    }
    template <class F> int max_right(int l, F f) const {
        assert(0 <= l && l <= _n);
        assert(f(e()));
        if (l == _n) return _n;
        l += size;
        T sm = e();
        do {
            while (l % 2 == 0) l >>= 1;
            if (!f(op(sm, d[l]))) {
                while (l < size) {
                    l = (2 * l);
                    if (f(op(sm, d[l]))) {
                        sm = op(sm, d[l]);
                        l++;
                    }
                }
                return l - size;
            }
            sm = op(sm, d[l]);
            l++;
        } while ((l & -l) != l);
        return _n;
    }
 
    // Binary search on SegTree to find smallest l:
    //    f(op(a[l] .. a[r-1])) = true      (assuming empty array is always true)
    //    f(op(a[l-1] .. a[r-1])) = false   (assuming op(a[-1], ..), which is out of bound, is always false)
    template <bool (*f)(T)> int min_left(int r) const {
        return min_left(r, [](T x) { return f(x); });
    }
    template <class F> int min_left(int r, F f) const {
        assert(0 <= r && r <= _n);
        assert(f(e()));
        if (r == 0) return 0;
        r += size;
        T sm = e();
        do {
            r--;
            while (r > 1 && (r % 2)) r >>= 1;
            if (!f(op(d[r], sm))) {
                while (r < size) {
                    r = (2 * r + 1);
                    if (f(op(d[r], sm))) {
                        sm = op(d[r], sm);
                        r--;
                    }
                }
                return r + 1 - size;
            }
            sm = op(d[r], sm);
        } while ((r & -r) != r);
        return 0;
    }
 
private:
    int _n, size, log;
    vector<T> d;
 
    void update(int k) {
        d[k] = op(d[2*k], d[2*k+1]);
    } 
};
 
Node op(Node x, Node y) {
    return x + y;
}
 
Node e() {return {-INF, -1};}
 
const int MAXN = 1e5 + 5;
int n, L, R;
// vector<array<int, 3>> edges;
vector<pii> adj[MAXN];
vector<array<int, 3>> depths;
bitset<MAXN> active;
int sz[MAXN], mxpath = 0, opt_u = -1, opt_v = -1;
int curcheck = 0;
vector<int> vals;
pii centroid_memo[MAXN];
 
void init() {
    cin >> n >> L >> R;
    for (int i = 1; i < n; ++i) {
        int u, v, w; cin >> u >> v >> w;
        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
        vals.push_back(w);
    }
}
 
void computeSz(int u, int par = 0) {
    sz[u] = 1;
    for (auto &e : adj[u]) {
        int v = e.fi;
        if (v == par || !active[v]) continue;
        computeSz(v, u);
        sz[u] += sz[v];
    }
}
 
int findCentroid(int u, int numNode, int par = 0) {
    for (auto &e : adj[u]) {
        int v = e.fi;
        if (!active[v] || v == par) continue;
        if (sz[v] > numNode / 2)
            return findCentroid(v, numNode,  u);
    }
 
    return u;
}
 
void getDepths(int u, vector<array<int, 3>> &info, int depth, int sumWeight, int par = 0) {
    if (depth > R) return;
    info.push_back({depth, sumWeight, u});
    for (auto &e : adj[u]) {
        int v = e.fi, w = (e.se >= curcheck ? 1 : -1);
        if (!active[v] || v == par) continue;
        getDepths(v, info, depth + 1, sumWeight + w, u);
    }
}
 
int step = 0;
bool centroid_decomposition(int curNode) {
    ++step;
    int centroid;
    if (centroid_memo[step].fi == 0) {
        computeSz(curNode);
        centroid = findCentroid(curNode, sz[curNode]);
        centroid_memo[step] = {centroid, sz[curNode]};
    } else {
        centroid = centroid_memo[step].fi;
        sz[curNode] = centroid_memo[step].se;
    }
 
    active[centroid] = 0;
 
    int segsz = min(sz[curNode], R);
    SegTree<Node, op, e> segmx(segsz + 5);
    segmx.set(0, {0, centroid});
 
    for (auto &e : adj[centroid]) {
        int v = e.fi, w = (e.se >= curcheck ? 1 : -1);
        if (!active[v]) continue;
 
        depths.clear();
        getDepths(v, depths, 1, w, centroid);
        // cout << v << "\n";
        for (auto &info : depths) {
            int len = info[0];
            // L <= len + pre <= R
            // L - len <= pre <= R - len
            if (R - len < 0) continue;
 
            int lo = max(0, L - len);
            int hi = min(segsz, R - len);
            if (lo > hi) continue;
            Node mxpre = segmx.prod(lo, hi + 1);
            if (mxpre.mxval == -INF) continue;
            int cost = info[1] + mxpre.mxval;
            if (cost > mxpath) {
                mxpath = cost;
                opt_u = info[2]; opt_v = mxpre.u;
            }
 
            if (mxpath >= 0) return 1;
        }
 
        for (auto &info : depths)
            if (info[0] <= segsz)
                segmx.set(info[0], {info[1], info[2]});
    }
 
    for (auto &e : adj[centroid]) {
        int v = e.fi;
        if (active[v] && centroid_decomposition(v)) 
            return 1;
    }
 
    return 0;
}
 
bool check(int x) {
    step = 0;
    mxpath = -1; opt_u = opt_v = -1;
    curcheck = x;
    for (int i = 1; i <= n; ++i) {
        active[i] = 1;
    }
 
    // for (auto &e : edges) {
    //     int u = e[0], v = e[1];
    //     int w = (e[2] >= x ? 1 : -1);
    //     adj[u].push_back({v, w});
    //     adj[v].push_back({u, w});
    // }
 
    return centroid_decomposition(1);
}
 
void solve() {
    // for (auto &e : edges) vals.push_back(e[2]);
    sort(all(vals));
    vals.erase(unique(all(vals)), end(vals));
 
    int lo = 0, hi = SZ(vals) - 1;
    int ans_u = 0, ans_v = 0;
    while (lo <= hi) {
        int mid = (lo + hi) >> 1;
        if (check(vals[mid])) {
            lo = mid + 1;
            ans_u = opt_u; ans_v = opt_v;
        } else hi = mid - 1;
    }
 
    cout << ans_u << ' ' << ans_v << '\n';
    // cout << ans;
}
 
signed main() {
    #ifdef NCTHANH
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif
    ios_base::sync_with_stdio(0);
    cin.tie(nullptr); cout.tie(nullptr);
 
    init();
    solve();
 
    return 0;
}