#include <bits/stdc++.h>
class union_find {
 private:
  std::vector<int> parent;
  std::vector<int> rank;
  int node_num;

 public:
  union_find(int node_num);
  void unite(int x, int y);
  int find(int x);
};
union_find::union_find(int node_num)
    : parent(node_num + 1, 0), rank(node_num + 1, 0) {
  for (int i = 0; i <= node_num; i++) {
    parent[i] = i;
  }
}
void union_find::unite(int x, int y) {
  int x_root = find(x);
  int y_root = find(y);
  if (x_root == y_root) return;
  if (rank[x_root] > rank[y_root]) {
    parent[y_root] = x_root;
  } else {
    parent[x_root] = y_root;
    if (rank[x_root] == rank[y_root]) {
      rank[y_root]++;
    }
  }
}
int union_find::find(int x) {
  if (x != parent[x]) {
    parent[x] = find(parent[x]);
  }
  return parent[x];
}
class edge {
 public:
  edge(int to, long long cost);
  int get_to() const;
  long long get_cost() const;

 private:
  int to;
  long long cost;
};
edge::edge(int to, long long cost) : to(to), cost(cost) {}
int edge::get_to() const { return to; }
long long edge::get_cost() const { return cost; }
class kruskal {
 private:
  std::unordered_map<int, std::vector<edge>> adj_list;
  std::unordered_map<int, std::vector<edge>> MST_list;
  int node_num;
  long long MST_cost;

 public:
  kruskal(const int node_num,
          const std::unordered_map<int, std::vector<edge>> &adj_list);
  long long get_MST_cost() const;
  std::unordered_map<int, std::vector<edge>> get_MST_list();
  void calc_MST();
};
kruskal::kruskal(const int node_num,
                 const std::unordered_map<int, std::vector<edge>> &adj_list)
    : adj_list(adj_list), node_num(node_num), MST_cost(0) {}
void kruskal::calc_MST() {
  std::vector<std::pair<long long, std::pair<int, int>>> edge_list;
  for (auto &v : adj_list) {
    for (auto &e : v.second) {
      edge_list.push_back(
          std::make_pair(e.get_cost(), std::make_pair(v.first, e.get_to())));
    }
  }
  std::sort(edge_list.begin(), edge_list.end());
  union_find uf(node_num + 1);
  MST_cost = 0;
  MST_list.clear();
  for (auto &ed : edge_list) {
    int v1 = ed.second.first;
    int v2 = ed.second.second;
    long long cost = ed.first;
    if (uf.find(v1) != uf.find(v2)) {
      uf.unite(v1, v2);
      MST_cost += cost;
      MST_list[v1].push_back(edge(v2, cost));
      MST_list[v2].push_back(edge(v1, cost));
    }
  }
}
long long kruskal::get_MST_cost() const { return MST_cost; }
std::unordered_map<int, std::vector<edge>> kruskal::get_MST_list() {
  return MST_list;
}
int main() {
  std::unordered_map<int, std::vector<edge>> adj_list;
  int N, M;
  std::cin >> N >> M;
  if (M == 0) {
    std::cout << 0 << "\n";
    return 0;
  }
  for (int i = 0; i < M; i++) {
    int s, t, w;
    std::cin >> s >> t >> w;
    adj_list[s].push_back(edge(t, w));
    adj_list[t].push_back(edge(s, w));
  }
  kruskal krus(N, adj_list);
  krus.calc_MST();
  std::cout << krus.get_MST_cost() << "\n";
  std::unordered_map<int, std::vector<edge>> MST = krus.get_MST_list();
  return 0;
}
