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

#include "bits/stdc++.h"
#define FI first.first
#define SE first.second
#define TH second
#define fi first
#define se second
#define th second

using namespace std;

string to_string(const string& str) {
  return str;
}

template<typename T>
string to_string(const set<T>& mys) {
  if(mys.empty()) return "{}";
  string ret = "{";
  for(auto el: mys) ret += to_string(el) + ", ";
  ret.pop_back(), ret.pop_back(); // Remove last space and comma
  ret += "}";
  return ret;
}

template<typename T>
string to_string(const pair<T, T>& pr) {
  return "(" + to_string(pr.fi) + "," + to_string(pr.se) + ")";
}

template<typename T>
string to_string(const vector<T>& vc, int w) {
  if(vc.empty()) return "";
  if(w + 1 == vc.size()) return to_string(vc[w]);
  return to_string(vc[w]) + "," + to_string(vc, w + 1);
}

template<typename T>
string to_string(const vector<T>& vc) {
  return "{" + to_string(vc, 0) + "}";
}

void debug_out() { cerr << endl; }
 
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  cerr << " " << to_string(H);
  debug_out(T...);
}
 
#ifdef DEBUG
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

class DebugStream {}LOG;
template <typename T>DebugStream &operator<<(DebugStream &s, const T&) { return s; }
#ifdef DEBUG
#define LOG clog
#endif

typedef long long ll;
typedef pair<ll, ll> ii;
typedef long double ld;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());

const int maxN = 2e5 + 9, maxV = 1e6 + 9, MOD = 1e9 + 7, SQ = 335, lg = 18, bs = 29;

struct Edg {
  int from, to, cost;
  bool operator<(const Edg& ot) const {
    return cost < ot.cost;
  }
};

vector<ii> fdg[maxN];
const int Tsz = 1 << lg;
int T[Tsz * 2], n, m, comp[maxN * 2], compEdgs[maxN], orig[maxN];
bool isTree[maxN], hasUnassigned[maxN * 2];
set<int> adj[maxN];
vector<vector<int>> comps;
vector<Edg> edgs;

void upd(int w, int x) {
  w += Tsz;
  T[w] = x;
  while(w > 1) {
    w >>= 1;
    T[w] = T[w << 1] + T[w << 1 | 1];
  }
}

void getUnv(vector<int>& vc, const set<int>& mys, int w = 1) {
  if(w >= Tsz) {
    if(!mys.count(w - Tsz)) {
      vc.push_back(w - Tsz);
      upd(w - Tsz, 0);
    }
    return;
  }
  if(T[w << 1]) getUnv(vc, mys, w << 1);
  if(T[w << 1 | 1]) getUnv(vc, mys, w << 1 | 1);
}

int get(int u) {
  if(u == -1) return -1;
  if(comp[u] == u) return u;
  return comp[u] = get(comp[u]);
}

int ffs(int src, int trg, int an = -1) {
  if(src == trg) return 1;
  int c = orig[src];
  if(orig[trg] == c) return 2;
  for(auto pr: fdg[c]) {
    if(pr.se == an) continue;
    int rsp = ffs(pr.se, trg, pr.fi);
    if(rsp == 0) continue;
    if(rsp == 2) return 2;
    if(pr.fi == src) return 1;
    return 2;
  }
  return 0;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  #ifdef DEBUG
  freopen("input.txt", "r", stdin);
  #endif

  cin >> n >> m;

  int xr = 0;
  for(int i = 0, u, v, c; i < m; i++) {
    cin >> u >> v >> c;
    u--, v--;
    adj[u].insert(v);
    adj[v].insert(u);
    edgs.push_back({ u, v, c });
    xr ^= c;
  }

  for(int i = 0; i < n; i++)
    upd(i, 1);

  auto prt = [&]() {
    for(int i = 0; i < n; i++) LOG << T[i + Tsz];
    LOG << '\n';
  };

  for(int i = 0; i < n; i++) {
    if(!T[i + Tsz]) continue;
    upd(i, 0);
    vector<int> q({i});
    for(int j = 0; j < q.size(); j++) {
      int nd = q[j];
      comp[nd + maxN] = comps.size();
      orig[nd] = comps.size();
      getUnv(q, adj[nd]);
    }
    comp[comps.size()] = comps.size();
    comps.push_back(q);
  }

  for(const auto& edg: edgs) {
    int u = comp[edg.from + maxN];
    int v = comp[edg.to + maxN];
    if(u == v)
      compEdgs[u]++;
  }

  bool selected = false;
  for(int i = 0; i < comps.size(); i++) {
    const auto& vc = comps[i];
    ll sz = vc.size();
    bool isTree = sz * (sz - 1) / 2 - compEdgs[i] == sz - 1;
    if(!isTree) selected = true;
  }

  ll sm = 0;
  if(!selected) edgs.push_back({-1, -1, xr});
  sort(edgs.begin(), edgs.end());

  int ct = 0;
  for(const auto& edg: edgs) {
    if(edg.from == -1) {
      if(!selected) {
        sm += xr;
        selected = true;
      }
      continue;
    }
    int rsp = ffs(edg.from, edg.to);
    /*if(ct++ == 1) {
      for(int i = 0; i < comps.size(); i++)
        debug(fdg[i]);
      debug(orig[1], orig[2], orig[3], orig[4]);
      debug(rsp, edg.from, edg.to, selected);
      exit(0);
    }*/
    if(rsp == 0) {
      sm += edg.cost;
      int a = orig[edg.from], b = orig[edg.to];
      fdg[a].emplace_back(edg.from, edg.to);
      fdg[b].emplace_back(edg.to, edg.from);
    } else if(!selected && rsp == 2) {
      selected = true;
      sm += edg.cost;
    }
  }

  cout << sm << '\n';
}

