#include <stdio.h>
#include <stdlib.h>
#define ll long long
#define rep(i,l,r)for(ll i=(l);i<(r);i++)

//辺の情報を個別に持つタイプ
typedef struct edge{ll s,g,c;}E;
typedef struct graph{
	int vcnt,ecnt;
	E  e[200010];//適宜変える
}G;

int csort(const void*a,const void*b){
	ll p=(*(E*)a).c,q=(*(E*)b).c;
	return p<q?-1:p>q?1:0;
}

G g;
void readgraph(){
	//適宜変える
	ll n,m;
	scanf("%lld%lld",&n,&m);
	rep(i,0,m){
		ll x,y,c;
		scanf("%lld%lld%lld",&x,&y,&c);
		g.e[2*i].s=x;
		g.e[2*i].g=y;
		g.e[2*i].c=c;
		g.e[2*i+1].s=y;
		g.e[2*i+1].g=x;
		g.e[2*i+1].c=c;
	}
	g.vcnt=n;
	g.ecnt=2*m;
	qsort(g.e,g.ecnt,sizeof(E),csort);

}

//union-find
#define UFLIMIT (1<<17)
int unicnt[UFLIMIT+10];//正ならcnt、非正なら根のindex
void ufinit(int n){rep(i,0,n)unicnt[i]=1;}
int ufroot(int x){return unicnt[x]<=0?-(unicnt[x]=-ufroot(-unicnt[x])):x;}
int ufsame(int x,int y){return ufroot(x)==ufroot(y);}
void uni(int x,int y){if((x=ufroot(x))==(y=ufroot(y)))return;if(unicnt[x]<unicnt[y]){int t=x;x=y;y=t;}unicnt[x]+=unicnt[y];unicnt[y]=-x;}
#undef UFLIMIT


//クラスカル法
//最小全域木を構成する辺とそのコストの合計を求める
//union findが必要、事前にコストでソートが必要
//O(ElogE)
//*
//ll saishou[100010];
ll kurasukaru(){
	ll ans=0;
	ufinit(g.vcnt);
	rep(i,0,g.ecnt){
		if(!ufsame(g.e[i].s,g.e[i].g)){
			uni(g.e[i].s,g.e[i].g);
//			saishou[i]=1;
			ans+=g.e[i].c;
		}
	}
	return ans;
}
//*/

int main(){
	readgraph();
	printf("%lld\n",kurasukaru());
}

