//  Created by conan1024hao in 2019.
//  Copyright © 2019 conan1024hao. All rights reserved.
//  専用ライブラリです、自由にコピーして構いません。
//  感谢看我的代码！Wechat:conan1024hao QQ:810396815
#pragma GCC optimize ("O3")
#include <iostream>
#include <iomanip>
#include <istream>
#include <ostream>
#include <sstream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <queue>
#include <deque>
#include <list>
#include <stack>
#include <map>
#include <set>
#include <utility>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <ctime>
#include <cctype>
#include <cstdlib>
#define INF 10e16
#define MOD 1000000007
#define  mod 1000000007
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define mmax(x,y)(x>y?x:y)
#define mmin(x,y)(x<y?x:y)
#define chmax(x,y) x=mmax(x,y)
#define chmin(x,y) x=mmin(x,y)
#define all(x) (x).begin(),(x).end()
#define siz(x) (ll)(x).size()
#define PI acos(-1.0)
using namespace std;
//using Int=int_fast64_t;
typedef long long int ll;
typedef pair<ll,ll>Pll;
typedef pair<int,int>Pin;
long long GCD(long long a, long long b) { return b ? GCD(b, a%b) : a; }
long long LCM(long long a, long long b)  {return a/GCD(a,b)*b;}
int dx[8]={-1,0,1,0,1,1,-1,-1};
int dy[8]={0,-1,0,1,1,-1,1,-1};
char dir[4]={'u','l','d','r'};
ll cmp1(pair<ll,string>a,pair<ll,string> b){
        if(a.fi!=b.fi)
        return a.fi<b.fi;
        else
        return a.se<b.se;
}
//--------------------------------------------------------------------------
struct unionfind{
    vector<int> rank,parent,size;
    unionfind(int n){
        for(int i=0;i<n;i++){
            rank.push_back(1);//树的高度
            parent.push_back(i);//根
            size.push_back(1);//树大小
        }
    }
    int getroot(int x){
        if(parent[x]==x)
            return x;
        return parent[x]=getroot(parent[x]);//押平路径加速以后的查找
    }
    bool issame(int a,int b){
        return getroot(a)==getroot(b);
    }
    void unite(int a,int b){
        a=getroot(a);
        b=getroot(b);
        if(a==b)
            return;
        else if(rank[a]>rank[b]){ //合并到高的树下
            parent[b]=a;
            size[a]+=size[b];
        }
        else if(rank[a]==rank[b]){
            parent[b]=a;
            rank[a]++;
            size[a]+=size[b];
        }
        else{
            parent[a]=b;
            size[b]+=size[a];
        }
    }
};

class Edge{
public:
    int source,target,cost;
    Edge(int source=0,int target=0,int cost=0):
    source(source), target(target), cost(cost) {}
    bool operator < ( const Edge &e) const {
        return cost < e.cost;
    }
};

int kruskal(int n,vector<Edge> edges){
    int total=0;
    sort(all(edges));
    unionfind uf(n);
    for(int i=0;i<edges.size();i++){
        Edge e=edges[i];
        if(!uf.issame(e.source, e.target)){
            total+=e.cost;
            uf.unite(e.source,e.target);
        }
    }
    return total;
}
//---------------------------------------------------------------------------
int main(){//問題をちゃんと見ろ!!!!!!!!!!!!!!!!!      llか??????????        memset()!!!!!!!!!!!!       ペナを減らせ!!!!!!!!!!!!!
    cin.tie(0);
    ios::sync_with_stdio(false);
    //-------------------------------
    int n,m,cost;
    int s,t;
    cin>>n>>m;
    vector<Edge> edges;
    for(int i=0;i<m;i++){
        cin>>s>>t>>cost;
        edges.pb(Edge(s,t,cost));
    }
    cout<< kruskal(n, edges)<<endl;
    //-------------------------------
    return 0;
}
//---------------------------------------------------------------------------







Measured memory_bytes: 5504