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