#include using namespace std; using ll = long long; struct UnionFind { private: int n_; std::vector parent_or_size_; int group_count_; public: explicit UnionFind(int n) : n_(n), parent_or_size_(n, -1), group_count_(n) {} bool merge(int u, int v) { assert(0 <= u && u < n_); assert(0 <= v && v < n_); u = root_internal(u); v = root_internal(v); if (u == v) { return false; } if (parent_or_size_[u] > parent_or_size_[v]) { std::swap(u, v); } parent_or_size_[u] += parent_or_size_[v]; parent_or_size_[v] = u; --group_count_; return true; } bool same(int u, int v) { assert(0 <= u && u < n_); assert(0 <= v && v < n_); return root_internal(u) == root_internal(v); } int root(int v) { assert(0 <= v && v < n_); return root_internal(v); } int size(int v) { assert(0 <= v && v < n_); return -parent_or_size_[root_internal(v)]; } int group_count() const { return group_count_; } std::vector> groups() { std::vector root_buf(n_); std::vector group_id(n_, -1); std::vector> result; result.reserve(group_count_); for (int i = 0; i < n_; ++i) { root_buf[i] = root_internal(i); } for (int i = 0; i < n_; ++i) { if (parent_or_size_[i] < 0) { group_id[i] = (int)result.size(); result.emplace_back(); result.back().reserve(-parent_or_size_[i]); } } for (int i = 0; i < n_; ++i) { result[group_id[root_buf[i]]].push_back(i); } return result; } private: int root_internal(int v) { if (parent_or_size_[v] < 0) { return v; } return parent_or_size_[v] = root_internal(parent_or_size_[v]); } }; int main() { cin.tie(nullptr); ios_base::sync_with_stdio(false); int N, M; cin >> N >> M; vector>> E(M); for (int i = 0; i < M; i++) { cin >> E[i].second.first >> E[i].second.second >> E[i].first; E[i].second.first--; E[i].second.second--; } sort(E.begin(), E.end()); UnionFind uf(N); ll ans = 0; for (int i = 0; i < M; i++) { if (!uf.same(E[i].second.first, E[i].second.second)) { ans += (ll)E[i].first * uf.size(E[i].second.first) * uf.size(E[i].second.second); uf.merge(E[i].second.first, E[i].second.second); } } cout << ans << '\n'; }