// AOJ GRL_2_A Minimum Spanning Tree
// 2018.4.26 bal4u

#include <stdio.h>
#include <string.h>

#define MAX_V 10002

/* UNION-FIND library */
int id[MAX_V], size[MAX_V];
void init(int n) { int i; for (i = 0; i < n; i++) id[i] = i, size[i] = 1; }
int root(int i) { while (i != id[i]) id[i] = id[id[i]], i = id[i]; return i; }
int connected(int p, int q) { return root(p) == root(q); }
void unite(int p, int q)
{
    int i = root(p), j = root(q); if (i == j) return;
    if (size[i] < size[j]) id[i] = j, size[j] += size[i]; else id[j] = i, size[i] += size[j];
}

typedef struct { int s, t, w; } EDGE;
EDGE edge[100002], edge2[100002], *end; int m;

#define VMAX 10000
int f[VMAX+1];

void distsort(int m)
{
	int i, x;
	EDGE *ep;

//	memset(f, 0, sizeof(f));
	end = edge + m;
	for (ep = edge; ep < end; ep++) f[ep->w]++;
	for (i = 0; i <= 10000; i++) f[i] += f[i-1];
	for (i = m-1; i >= 0; i--) {
		x = edge[i].w, edge2[--f[x]] = edge[i];
	}
}

int kruskal(int V, int E)
{
	int ans;
	EDGE *ep;

	distsort(E);
	init(V); 
	ans = 0;
	ep = edge2;	while (E--) {
		if (!connected(ep->s, ep->t)) { 
			unite(ep->s, ep->t);
			ans += ep->w;
		}
		ep++;
	}
	return ans;
}

//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0, c = getchar_unlocked();
	do n = 10*n + (c & 0xf), c = getchar_unlocked(); while (c >= '0');
	return n;
}

int main()
{
	int V, E, i;

	V = in(), E = in();
	for (i = 0; i < E; i++) {
		edge[i].s = in(), edge[i].t = in(), edge[i].w = in();
	}
	printf("%d\n", kruskal(V, E));
	return 0;
}

