#include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "functional"
#include "ctime"

using namespace std;

constexpr long long int MOD = 1000000007;
//constexpr int MOD = 1000000007;
//constexpr int MOD = 998244353;
//constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-8;

//int N, M, K, H, W, L, R;
long long int N, M, K, H, W, L, R;

template< typename T >
struct edge {
	int src, to;
	T cost;

	edge(int to, T cost) : src(-1), to(to), cost(cost) {}

	edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}

	edge &operator=(const int &x) {
		to = x;
		return *this;
	}

	operator int() const { return to; }
};

template< typename T >
using Edges = vector< edge< T > >;
template< typename T >
using WeightedGraph = vector< Edges< T > >;
using UnWeightedGraph = vector< vector< int > >;
template< typename T >
using Matrix = vector< vector< T > >;

template< typename G >
struct LowLink {
	const G &g;
	vector< int > used, ord, low;
	vector< int > articulation;
	vector< pair< int, int > > bridge;

	LowLink(const G &g) : g(g) {}

	int dfs(int idx, int k, int par) {
		used[idx] = true;
		ord[idx] = k++;
		low[idx] = ord[idx];
		bool is_articulation = false;
		int cnt = 0;
		for (auto &to : g[idx]) {
			if (!used[to]) {
				++cnt;
				k = dfs(to, k, idx);
				low[idx] = min(low[idx], low[to]);
				is_articulation |= ~par && low[to] >= ord[idx];
				if (ord[idx] < low[to]) bridge.emplace_back(minmax(idx, (int)to));
			}
			else if (to != par) {
				low[idx] = min(low[idx], ord[to]);
			}
		}
		is_articulation |= par == -1 && cnt > 1;
		if (is_articulation) articulation.push_back(idx);
		return k;
	}

	virtual void build() {
		used.assign(g.size(), 0);
		ord.assign(g.size(), 0);
		low.assign(g.size(), 0);
		int k = 0;
		for (int i = 0; i < g.size(); i++) {
			if (!used[i]) k = dfs(i, k, -1);
		}
	}
};

void Calculate_Depth(vector<vector<pair<int,int>>>&edge, vector<int>&depth, int stnode) {
	depth[stnode] = 0;
	queue<int>Q;
	Q.push(stnode);
	while (!Q.empty()) {
		int cn = Q.front();
		Q.pop();
		for (auto i : edge[cn]) {
			if (depth[i.first] > depth[cn] + 1) {
				depth[i.first] = depth[cn] + 1;
				Q.push(i.first);
			}
		}
	}
	return;
}

void Search(vector<vector<pair<int, int>>>&edge, vector<int>&depth, vector<int>&used, vector<int>&visited,vector<long long int>&sum, int node = 0) {
	for (auto i : edge[node]) {
		if (depth[i.first] < depth[node])continue;
		if (depth[i.first] == depth[node]) {
			if (i.first < node)continue;
		}
		if (!visited[i.first]) {
			visited[i.first]++;
			Search(edge, depth, used, visited, sum, i.first);
		}
		if (depth[i.first] > depth[node]) {
			if (!used[i.first]) {
				used[i.first]++;
				sum[node] += sum[i.first];
			}
		}
		sum[node] += i.second;
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin >> N >> M;
	UnWeightedGraph g(N);
	vector<vector<pair<int, int>>>e(N);
	vector<int>depth(N, MOD);
	long long int mx = 0;
	for (int i = 0; i < M; i++) {
		cin >> L >> R >> K;
		L--, R--;
		mx += K;
		e[L].push_back({ R,K });
		e[R].push_back({ L,K });
		g[L].push_back(R);
		g[R].push_back(L);
	}
	Calculate_Depth(e, depth, 0);
	LowLink< UnWeightedGraph > lowlink(g);
	lowlink.build();
	sort(lowlink.bridge.begin(), lowlink.bridge.end());
	vector<long long int>sum(N);
	vector<int>visited(N);
	vector<int>used(N);
	Search(e, depth, used,visited, sum);
	unordered_set<long long int>st;
	for (auto i : lowlink.bridge)st.insert( min(i.first,i.second)*MOD+max(i.first,i.second) );
	pair<int, int>ans(MOD, MOD);
	long long int answeight = MOD * MOD;
	for (int i = 0; i < N; i++) {
		for (auto j : e[i]) {
			if (answeight > mx - j.second) {
				answeight = mx - j.second;
				ans = { min(i,j.first),max(i,j.first) };
			}
			if (answeight >= mx - j.second) {
				answeight = mx - j.second;
				ans = min(ans, { min(i,j.first),max(i,j.first) });
			}
			if (depth[j.first] <= depth[i])continue;
			if (st.find( min(i,j.first)*MOD+max(i,j.first) ) == st.end())continue;
			long long int weight = abs(mx - j.second - sum[j.first] * 2);
			if (answeight >= weight) {
				if (answeight > weight) {
					ans = { min(i,j.first),max(i,j.first) };
				}
				answeight = weight;
				ans = min(ans, { min(i,j.first),max(i,j.first) });
			}
		}
	}
	cout << ans.first + 1 << " " << ans.second + 1 << endl;
}


Measured memory_bytes: 22828