// Slower C++ solution:
#include <iostream>

#include <vector>

#include <algorithm>

using namespace std;

struct edge{

    int u,v,cost;

    bool operator<(const edge& v) const {

        return cost < v.cost;

    }

};

const int INF = 1001001001;

const edge imEg = {-1,-1,INF};

vector<edge> es(10000, imEg);

int V,E;

vector<int> par;

vector<int> rnk;



void init_union_find(int n) {

    par.resize(n);

    rnk.resize(n);

    for(int i=0; i<n; i++) {

        par[i] = i;

        rnk[i] = 0;

    }

}



int find(int x) {

    if(x != par[x]) par[x] = find(par[x]);

    return par[x]; 

}



void unite(int x, int y) {

    x = find(x);

    y = find(y);

    if(x == y) return;

    if(rnk[x] > rnk[y]) par[y] = x;

    else par[x] = y;

    if(rnk[x] == rnk[y]) rnk[y]++;

}



int kruskal() {

    init_union_find(V);

    sort(es.begin(), es.end());

    int res = 0;

    for(int i=0; i<E; i++) {

        edge e = es[i];

        if(find(e.u) != find(e.v)) {

            unite(e.u, e.v);

            res += e.cost;

        }

    }

    return res;

}



int main() {

    cin >> V >> E;

    es.resize(E);

    for(int i=0; i<E; i++) {

        int s,t,w;

        cin >> s >> t >> w;

        struct edge e = {s,t,w};

        es[i] = e;

    }

    cout << kruskal() << endl;

    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 1.1134634688303313x):
#ifndef TKLIB_KRUSKAL_HPP

#define TKLIB_KRUSKAL_HPP



#ifndef UNION_FIND_HPP

#define UNION_FIND_HPP



#include <vector>



namespace tklib {



class UnionFind {

private:

    std::vector<int> par;

    int components;



public:

    UnionFind(int n) : par(n, -1), components(n) {}



    bool unite(int x, int y) {

        if ((x = find(x)) == (y = find(y))) {

            return false;

        } else {

            if (par[x] < par[y]) std::swap(x, y);

            par[y] += par[x];

            par[x] = y;

            --components;

            return true;

        }

    }



    int find(int x) {

        if (par[x] < 0) return x;

        else return par[x] = find(par[x]);

    }



    int size(int x) {

        return -par[find(x)];

    }



    int count() {

        return components;

    }

};



} // namespace tklib



#endif // UNION_FIND_HPP



#include <algorithm>

#include <vector>

#include <tuple>



namespace tklib {



template <typename T>

auto kruskal(std::size_t V, std::vector<std::tuple<int, int, T>> &G) {

    using edge_type = std::tuple<int, int, T>;



    std::sort(begin(G), end(G), 

    [](const edge_type &lhs, const edge_type &rhs)

    { return std::get<2>(lhs) < std::get<2>(rhs); });

    

    tklib::UnionFind uf(V);

    std::vector<edge_type> edgelist;



    for(edge_type &edge : G) {

        if(uf.unite(std::get<0>(edge), std::get<1>(edge))) {

            edgelist.push_back(edge);

        }

    }



    return edgelist;

}



} // namespace tklib



#endif // TKLIB_KRUSKAL_HPP



#include <iostream>

#include <vector>

#include <tuple>

using namespace std;



int main() {

    int V, E;

    cin >> V >> E;

    vector<tuple<int, int, int>> G;

    while(E--) {

        int s, t, w;

        cin >> s >> t >> w;

        G.emplace_back(s, t, w);

    }



    auto edgelist = tklib::kruskal(V, G);

    int weight_sum = 0;

    for(auto e : edgelist) weight_sum += get<2>(e);

    cout << weight_sum << '\n';

}