#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Edge {
int u, v, weight;
bool operator<(const Edge& other) const {
return weight < other.weight;
}
};
struct UnionFind {
vector<int> parent, rank;
UnionFind(int n) : parent(n), rank(n, 0) {
for (int i = 0; i < n; ++i) parent[i] = i;
}
int find(int x) {
if (parent[x] != x) parent[x] = find(parent[x]);
return parent[x];
}
void unite(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
if (rank[rootX] < rank[rootY]) swap(rootX, rootY);
parent[rootY] = rootX;
if (rank[rootX] == rank[rootY]) rank[rootX]++;
}
}
};
int kruskal(int n, vector<Edge>& edges) {
sort(edges.begin(), edges.end());
UnionFind uf(n);
int mstWeight = 0;
for (auto& edge : edges) {
if (uf.find(edge.u) != uf.find(edge.v)) {
uf.unite(edge.u, edge.v);
mstWeight += edge.weight;
}
}
return mstWeight;
}
int main() {
int n, m;
cin >> n >> m;
vector<Edge> edges(m);
for (int i = 0; i < m; ++i) {
cin >> edges[i].u >> edges[i].v >> edges[i].weight;
edges[i].u--; edges[i].v--;
}
cout << kruskal(n, edges) << endl;
return 0;
}