2 0
 6 8
1 4 1
1 5 1
1 6 1
2 4 1
2 5 1
2 6 1
3 5 1
3 6 1
 6 12
1 3 8763000
1 4 8763000
1 5 8763000
1 6 8763000
2 3 8763000
2 4 1
2 5 8763000
2 6 1
3 5 8763000
3 6 8763000
4 5 8763000
4 6 2

0
 0
 8763002

//stan hu tao
//come to K-expo!!!
//watch me get carried in nct ridin
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Math.abs;
import static java.lang.System.out;
import java.util.*;
import java.io.*;
import java.math.*;

public class x1508C
{
    //static ArrayDeque<Edge>[] edges;
    static final long CONS = 696969L;
    public static void main(String hi[]) throws Exception
    {
        FastScanner infile = new FastScanner();
        int N = infile.nextInt();
        int M = infile.nextInt();
        /*
        edges = new ArrayDeque[N];
        for(int i=0; i < N; i++)
            edges[i] = new ArrayDeque<Edge>();
         */
        long xorTotal = 0;
        Edge[] edges = new Edge[M];
        HashSet<Long> setEdges = new HashSet<Long>(); //for 0 edge component checking
        for(int i=0; i < M; i++)
        {
            int a = infile.nextInt()-1;
            int b = infile.nextInt()-1;
            if(a > b)
                a = (a+b)-(b=a);
            int w = infile.nextInt();
            //edges[a].add(new Edge(b, w));
            //edges[b].add(new Edge(a, w));
            edges[i] = new Edge(a, b, w);
            setEdges.add(CONS*a+b);
            xorTotal ^= (long)w;
        }
        //connect components with 0-edges
        HashSet<Integer> active = new HashSet<Integer>();
        for(int v=0; v < N; v++)
            active.add(v);
        int[] comp = new int[N];
        Arrays.fill(comp, -1);
        int boof = 0;
        for(int v=0; v < N; v++)
            if(comp[v] == -1)
            {
                comp[v] = boof;
                ArrayDeque<Integer> q = new ArrayDeque<Integer>();
                q.add(v);
                active.remove(v);
                while(q.size() > 0)
                {
                    int curr = q.poll();
                    ArrayDeque<Integer> remove = new ArrayDeque<Integer>();

                    if(debug){
                        System.out.println("curr: "+curr);
                        print(active);
                    }

                    for(int next: active)
                    {
                        long key = CONS*min(curr, next)+max(curr, next);
                        if(!setEdges.contains(key))
                        {
                            q.add(next);
                            comp[next] = boof;
                            remove.add(next);
                        }
                    }
                    for(int x: remove)
                        active.remove(x);
                }
                boof++;
            }
        //count how many 0-edges exist
        //pigeonhole tells us whether every component is a tree or not
        long zeroCnt = (long)N*(N-1)/2;
        zeroCnt -= M;
        int treeEdges = N-boof;
        boolean addOn = false;
        if(zeroCnt == treeEdges)
            addOn = true;
        //find answer
        Arrays.sort(edges);
        DSU union = new DSU(N);
        int[] links = new int[boof];
        Arrays.fill(links, -1);
        for(int v=0; v < N; v++)
        {
            if(links[comp[v]] == -1)
                links[comp[v]] = v;
            else if(union.find(v) != union.find(links[comp[v]]))
                union.merge(v, links[comp[v]]);
        }
        //find answer
        long res = 0L;
        if(addOn)
        {
            //find minimum over all "useless" edges
            long choice = xorTotal;
            for(Edge e: edges)
                if(union.find(e.from) == union.find(e.to))
                    choice = min(choice, e.weight);
            res += choice;
            //is this the best option?
            //nah just submit KEKW
        }
        for(Edge e: edges)
            if(union.find(e.from) != union.find(e.to))
            {
                res += e.weight;
                union.merge(e.from, e.to);
            }
        System.out.println(res);
    }
    static boolean debug = false;
    public static void print(HashSet<Integer> edge)
    {
        for(int x: edge)
            System.out.print(x+" ");
        System.out.println();
    }
}
class Edge implements Comparable<Edge>
{
    public int from;
    public int to;
    public int weight;

    public Edge(int s, int a, int b)
    {
        from = s;
        to = a;
        weight = b;
    }
    public int compareTo(Edge oth)
    {
        if(weight == oth.weight)
            return 0;
        else if(weight < oth.weight)
            return -1;
        return 1;
    }
}
/*
NOTICE 0 IS NEVER PREASSIGNED
AT LEAST ONE 0 EDGE EXISTS
first determine connected components in 0-edge induced subgraph
For each predetermined edge, if it connects two in same component, ignore it (??)
Notice that only predetermined edges can connect components now

How to account for XOR = 0?
Is it optimal to change exactly one 0 edge? (or none if XOR already equals 0)
1) estimate how many 0-edges exist
2) if small, check if every component forms a tree
3) if at least one extra 0 edge exists, ignore the edge weight!
3) otherwise just add XOR to answer
take all "useful" edges and sort them (Kruskal)
 */
class DSU
{
    public int[] dsu;

    public DSU(int N)
    {
        dsu = new int[N+1];
        for(int i=0; i <= N; i++)
            dsu[i] = i;
    }
    public int find(int x)
    {
        return dsu[x] == x ? x : (dsu[x] = find(dsu[x]));
    }
    public void merge(int x, int y)
    {
        int fx = find(x);
        int fy = find(y);
        dsu[fx] = fy;
    }
}
class FastScanner
{
    private int BS = 1 << 16;
    private char NC = (char) 0;
    private byte[] buf = new byte[BS];
    private int bId = 0, size = 0;
    private char c = NC;
    private double cnt = 1;
    private BufferedInputStream in;

    public FastScanner() {
        in = new BufferedInputStream(System.in, BS);
    }

    public FastScanner(String s) {
        try {
            in = new BufferedInputStream(new FileInputStream(new File(s)), BS);
        } catch (Exception e) {
            in = new BufferedInputStream(System.in, BS);
        }
    }

    private char getChar() {
        while (bId == size) {
            try {
                size = in.read(buf);
            } catch (Exception e) {
                return NC;
            }
            if (size == -1) return NC;
            bId = 0;
        }
        return (char) buf[bId++];
    }

    public int nextInt() {
        return (int) nextLong();
    }

    public int[] nextInts(int N) {
        int[] res = new int[N];
        for (int i = 0; i < N; i++) {
            res[i] = (int) nextLong();
        }
        return res;
    }

    public long[] nextLongs(int N) {
        long[] res = new long[N];
        for (int i = 0; i < N; i++) {
            res[i] = nextLong();
        }
        return res;
    }

    public long nextLong() {
        cnt = 1;
        boolean neg = false;
        if (c == NC) c = getChar();
        for (; (c < '0' || c > '9'); c = getChar()) {
            if (c == '-') neg = true;
        }
        long res = 0;
        for (; c >= '0' && c <= '9'; c = getChar()) {
            res = (res << 3) + (res << 1) + c - '0';
            cnt *= 10;
        }
        return neg ? -res : res;
    }

    public double nextDouble() {
        double cur = nextLong();
        return c != '.' ? cur : cur + nextLong() / cnt;
    }

    public double[] nextDoubles(int N) {
        double[] res = new double[N];
        for (int i = 0; i < N; i++) {
            res[i] = nextDouble();
        }
        return res;
    }

    public String next() {
        StringBuilder res = new StringBuilder();
        while (c <= 32) c = getChar();
        while (c > 32) {
            res.append(c);
            c = getChar();
        }
        return res.toString();
    }

    public String nextLine() {
        StringBuilder res = new StringBuilder();
        while (c <= 32) c = getChar();
        while (c != '\n') {
            res.append(c);
            c = getChar();
        }
        return res.toString();
    }

    public boolean hasNext() {
        if (c > 32) return true;
        while (true) {
            c = getChar();
            if (c == NC) return false;
            else if (c > 32) return true;
        }
    }
}