package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"math"
	"os"
)

type Edge struct {
	HeadVertexID int
	HeadVertex   *Vertex
	TailVertexID int
	TailVertex   *Vertex
	Cost         int
}
type Vertex struct {
	ID           int
	EdgesFrom    []*Edge
	EdgesTo      []*Edge
	CheapestEdge int // The cheapest edge that crosses the boundary
	Index        int     // Index of item in heap
}
func (v *Vertex) AddFromEdge(e *Edge) {
	v.EdgesFrom = append(v.EdgesFrom, e)
}
func (v *Vertex) AddToEdge(e *Edge) {
	v.EdgesTo = append(v.EdgesTo, e)
}
type VertexHeap []*Vertex
func (vh VertexHeap) Len() int           { return len(vh) }
func (vh VertexHeap) Less(i, j int) bool { return vh[i].CheapestEdge < vh[j].CheapestEdge }
func (vh VertexHeap) Swap(i, j int) {
	vh[i], vh[j] = vh[j], vh[i]
	vh[i].Index = i
	vh[j].Index = j
}

func (vh *VertexHeap) Push(x interface{}) {
	n := len(*vh)
	v := x.(*Vertex)
	v.Index = n
	*vh = append(*vh, v)
}
func (vh *VertexHeap) Pop() interface{} {
	old := *vh
	n := len(old)
	v := old[n-1]
	v.Index = -1 // for safety, identify it's no longer in heap
	*vh = old[0 : n-1]
	return v
}
func (vh VertexHeap) Peek() {
	n := len(vh)
	if n == 0 {
		return
	}
}
// Update modifies the DGS of a Vertex in the heap.
func (vh *VertexHeap) UpdateHeap(v *Vertex) {
	for _, e := range v.EdgesTo {
		if e.TailVertex.Index > -1 && (e.Cost < e.TailVertex.CheapestEdge) {
			e.TailVertex.CheapestEdge = e.Cost
			heap.Fix(vh, e.TailVertex.Index)
		}
	}
	for _, e := range v.EdgesFrom {
		if e.HeadVertex.Index > -1 && (e.Cost < e.HeadVertex.CheapestEdge) {
			e.HeadVertex.CheapestEdge = e.Cost
			heap.Fix(vh, e.HeadVertex.Index)
		}
	}
}

var vh VertexHeap
var VertexMap = make(map[int]*Vertex)
func main() {

	var in = bufio.NewReader(os.Stdin)
	var n, q int
	fmt.Fscanf(in, "%d %d\n", &n, &q)
	var HeadVertexID,TailVertexID,EdgeCost int
	for i := 0; i < q; i++ {
		fmt.Fscanf(in, "%d %d %d\n", &HeadVertexID,&TailVertexID,&EdgeCost)
		h, ok := VertexMap[HeadVertexID]
		if !ok {
			h = &Vertex{
				HeadVertexID,  // Vertex ID		ID           int
				*new([]*Edge), // Edges From		EdgesFrom    []*Edge
				*new([]*Edge), // Edges To		EdgesTo      []*Edge
				math.MaxInt32,   // Cheapest edge	CheapestEdge float64 // The cheapest edge that crosses the boundary
				-1,            // Index			Index        int     // Index of item in heap
			}
			VertexMap[HeadVertexID] = h
		}
		t, ok := VertexMap[TailVertexID]
		if !ok {
			t = &Vertex{
				TailVertexID,  // Vertex ID		ID           int
				*new([]*Edge), // Edges From		EdgesFrom    []*Edge
				*new([]*Edge), // Edges To		EdgesTo      []*Edge
				math.MaxInt32,   // Cheapest edge	CheapestEdge float64
				-1,            // Index			Index        int
			}
			VertexMap[TailVertexID] = t
		}
		EdgeOneDir := &Edge{HeadVertexID, h, TailVertexID, t, EdgeCost}
		EdgeOtherDir := &Edge{TailVertexID, t, HeadVertexID, h, EdgeCost}

		h.AddToEdge(EdgeOneDir)
		h.AddFromEdge(EdgeOtherDir)
		t.AddFromEdge(EdgeOneDir)
		t.AddToEdge(EdgeOtherDir)
	}
	makeVertexHeap()
	minspancost := prim()
	fmt.Printf("%d\n", minspancost)
}
func makeVertexHeap() {
	vh = make(VertexHeap, len(VertexMap))
	i := 0
	for _, v := range VertexMap {
		v.Index = i
		vh[i] = v
		i++
	}
	heap.Init(&vh)
}

func prim() int {
	var MinSpanCost int
	MinSpanCost = 0
	if vh.Len() > 0 {
	    workingVertex := heap.Pop(&vh).(*Vertex)
	    vh.UpdateHeap(workingVertex)
    	for vh.Len() > 0 {
	    	workingVertex = heap.Pop(&vh).(*Vertex)
		    MinSpanCost += workingVertex.CheapestEdge
		    vh.UpdateHeap(workingVertex)
    	}
	}
	return MinSpanCost
}



Measured memory_bytes: 20404