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

#line 1 "c.cpp"
/*
  Author     : MatsuTaku
  Date         : 04/16/21
  Certificate:
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAAAgQDF9T447OEo8XSQ6O1AznN5tKC8mzvYc4Zs3+oOKfMqgLXfOwQnpfcoxKs4MAP1eICBD13PkcIezJ9IlV6nKQZKs1BQmvjSXJ+zKK8YCKvAueNPuNO0Bim43IBaNHNFWcMvcmUvHgRb6hUSO0V8I7OsjiFo20KDBj3gAznu9tir0Q==
CompetitiveProgrammingCertification:tkm.matsumoto@gmail.com
*/

#include <bits/stdc++.h>
using namespace std;
#include <x86intrin.h>
#line 4 "/mnt/c/Users/tkmma/competitive_programming/CPBF/library/include/unionfind.hpp"

class UnionFind {
private:
  std::vector<int> par_, sz_;

public:
  explicit UnionFind(size_t size) : par_(size), sz_(size, 1) {
    std::iota(par_.begin(), par_.end(), 0);
  }

  int root(int u) {
    if (u == par_[u])
      return u;
    return par_[u] = root(par_[u]);
  }

  bool are_union(int u, int v) { return root(u) == root(v); }

  int size_of(int u) { return sz_[root(u)]; }

  bool unite(int u, int v) {
    if (are_union(u, v))
      return false;
    if (size_of(u) < size_of(v))
      std::swap(u, v);
    sz_[root(u)] += size_of(v);
    par_[root(v)] = root(u);
    return true;
  }
};

#line 12 "c.cpp"
#define REP(i, f, n) for (auto i = (f), i##_len = (n); i < i##_len; i++)
#define rep(i, n) REP(i, (int)0, n)
#define RREP(i, f, n) for (auto i = (n)-1, i##_left = (f); i >= i##_left; i--)
#define rrep(i, n) RREP(i, (int)0, n)
using lint = long long int;
using ulint = unsigned long long int;
template <typename T> using vvec = vector<vector<T>>;
template <typename T> vvec<T> make_vvec(int n, int m, T v) {
  return vvec<T>(n, vector<T>(m, v));
}
template <typename T> T &chmax(T &dst, T x) { return dst = max(dst, x); }
template <typename T> T &chmin(T &dst, T x) { return dst = min(dst, x); }

class Solver {
public:
  Solver();
  void solve();
};

Solver::Solver() {}

using Edge = tuple<int, int, int>;

void Solver::solve() {
  int n, m;
  cin >> n >> m;
  vector<Edge> E(m);
  vector<unordered_set<int>> G(n);
  vector<int> D(n);
  int x = 0;
  rep(i, m) {
    int u, v, w;
    cin >> u >> v >> w;
    u--;
    v--;
    G[u].insert(v);
    G[v].insert(u);
    D[u]++;
    D[v]++;
    E[i] = {w, u, v};
    x ^= w;
  }
  UnionFind cdsu(n);
  unordered_set<int> uc;
  rep(i, n) uc.insert(i);
  int rem = 0;
  while (!uc.empty()) {
    int i = *uc.begin();
    uc.erase(uc.begin());
    rem++;
    //    if (D[i] == n-1) continue;
    queue<int> Q;
    Q.push(i);
    while (!Q.empty()) {
      int q = Q.front();
      Q.pop();
      vector<int> tmp;
      for (auto j : uc) {
        if (j == q)
          continue;
        if (G[q].count(j))
          continue;
        if (!cdsu.are_union(q, j)) {
          tmp.push_back(j);
        }
      }
      for (auto j : tmp) {
        uc.erase(j);
        cdsu.unite(q, j);
        Q.push(j);
      }
    }
  }

  lint ans = 0;
  UnionFind dsu(n);
  sort(E.begin(), E.end());
  for (auto [w, u, v] : E) {
    if (cdsu.are_union(u, v)) {
      if (!dsu.are_union(u, v)) {
        chmin(x, w);
      }
    } else {
      cdsu.unite(u, v);
      dsu.unite(u, v);
      ans += w;
    }
  }
  if ((lint)n * (n - 1) / 2 - m == n - rem) {
    ans += x;
  }
  cout << ans << endl;
}

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);
  Solver solver;
  int t = 1;
  //  cin>>t;
  while (t--) {
    solver.solve();
  }
  return 0;
}
