#include <bits/stdc++.h>
using namespace std;
string to_string(string s) { return '"' + s + '"'; }
string to_string(const char *s) { return to_string((string)s); }
string to_string(bool b) { return (b ? "true" : "false"); }
template <typename A, typename B>
string to_string(pair<A, B> p) {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}
template <typename A>
string to_string(A v) {
  bool first = true;
  string res = "{";
  for (const auto &x : v) {
    if (!first) {
      res += ", ";
    }
    first = false;
    res += to_string(x);
  }
  res += "}";
  return res;
}
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  cerr << " " << to_string(H);
  debug_out(T...);
}
template <typename T>
void dout(string name, int idx, T arg) {
  cerr << name << " = " << to_string(arg);
}
template <typename T1, typename... T2>
void dout(string names, int idx, T1 arg, T2... args) {
  cerr << names.substr(0, names.find(',')) << " = " << to_string(arg) << ", ";
  dout(names.substr(names.find(',') + 2), idx + 1, args...);
}
class segtree {
 public:
  struct node {
    int sum = 0;
    void apply(int l, int r, int v) { sum += v; }
  };
  node unite(const node &a, const node &b) const {
    node res;
    res.sum = a.sum + b.sum;
    return res;
  }
  inline void push(int x, int l, int r) {
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
  }
  inline void pull(int x, int z) { tree[x] = unite(tree[x + 1], tree[z]); }
  int n;
  vector<node> tree;
  void build(int x, int l, int r) {
    if (l == r) {
      return;
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    build(x + 1, l, y);
    build(z, y + 1, r);
    pull(x, z);
  }
  template <typename M>
  void build(int x, int l, int r, const vector<M> &v) {
    if (l == r) {
      tree[x].apply(l, r, v[l]);
      return;
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    build(x + 1, l, y, v);
    build(z, y + 1, r, v);
    pull(x, z);
  }
  node get(int x, int l, int r, int ll, int rr) {
    if (ll <= l && r <= rr) {
      return tree[x];
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    push(x, l, r);
    node res{};
    if (rr <= y) {
      res = get(x + 1, l, y, ll, rr);
    } else {
      if (ll > y) {
        res = get(z, y + 1, r, ll, rr);
      } else {
        res = unite(get(x + 1, l, y, ll, rr), get(z, y + 1, r, ll, rr));
      }
    }
    pull(x, z);
    return res;
  }
  template <typename... M>
  void modify(int x, int l, int r, int ll, int rr, const M &...v) {
    if (ll <= l && r <= rr) {
      tree[x].apply(l, r, v...);
      return;
    }
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    push(x, l, r);
    if (ll <= y) {
      modify(x + 1, l, y, ll, rr, v...);
    }
    if (rr > y) {
      modify(z, y + 1, r, ll, rr, v...);
    }
    pull(x, z);
  }
  int find_first_knowingly(int x, int l, int r,
                           const function<bool(const node &)> &f) {
    if (l == r) {
      return l;
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res;
    if (f(tree[x + 1])) {
      res = find_first_knowingly(x + 1, l, y, f);
    } else {
      res = find_first_knowingly(z, y + 1, r, f);
    }
    pull(x, z);
    return res;
  }
  int find_first(int x, int l, int r, int ll, int rr,
                 const function<bool(const node &)> &f) {
    if (ll <= l && r <= rr) {
      if (!f(tree[x])) {
        return -1;
      }
      return find_first_knowingly(x, l, r, f);
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res = -1;
    if (ll <= y) {
      res = find_first(x + 1, l, y, ll, rr, f);
    }
    if (rr > y && res == -1) {
      res = find_first(z, y + 1, r, ll, rr, f);
    }
    pull(x, z);
    return res;
  }
  int find_last_knowingly(int x, int l, int r,
                          const function<bool(const node &)> &f) {
    if (l == r) {
      return l;
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res;
    if (f(tree[z])) {
      res = find_last_knowingly(z, y + 1, r, f);
    } else {
      res = find_last_knowingly(x + 1, l, y, f);
    }
    pull(x, z);
    return res;
  }
  int find_last(int x, int l, int r, int ll, int rr,
                const function<bool(const node &)> &f) {
    if (ll <= l && r <= rr) {
      if (!f(tree[x])) {
        return -1;
      }
      return find_last_knowingly(x, l, r, f);
    }
    push(x, l, r);
    int y = (l + r) >> 1;
    int z = x + ((y - l + 1) << 1);
    int res = -1;
    if (rr > y) {
      res = find_last(z, y + 1, r, ll, rr, f);
    }
    if (ll <= y && res == -1) {
      res = find_last(x + 1, l, y, ll, rr, f);
    }
    pull(x, z);
    return res;
  }
  segtree(int _n) : n(_n) {
    assert(n > 0);
    tree.resize(2 * n - 1);
    build(0, 0, n - 1);
  }
  template <typename M>
  segtree(const vector<M> &v) {
    n = v.size();
    assert(n > 0);
    tree.resize(2 * n - 1);
    build(0, 0, n - 1, v);
  }
  node get(int ll, int rr) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    return get(0, 0, n - 1, ll, rr);
  }
  node get(int p) {
    assert(0 <= p && p <= n - 1);
    return get(0, 0, n - 1, p, p);
  }
  template <typename... M>
  void modify(int ll, int rr, const M &...v) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    modify(0, 0, n - 1, ll, rr, v...);
  }
  int find_first(int ll, int rr, const function<bool(const node &)> &f) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    return find_first(0, 0, n - 1, ll, rr, f);
  }
  int find_last(int ll, int rr, const function<bool(const node &)> &f) {
    assert(0 <= ll && ll <= rr && rr <= n - 1);
    return find_last(0, 0, n - 1, ll, rr, f);
  }
};
class DSU {
 public:
  vector<int> p;
  int n;
  DSU(int _n) : n(_n) {
    p.resize(n);
    iota(p.begin(), p.end(), 0);
  }
  inline int get(int x) { return (x == p[x] ? x : (p[x] = get(p[x]))); }
  inline bool unite(int x, int y) {
    x = get(x);
    y = get(y);
    if (x != y) {
      p[x] = y;
      return true;
    }
    return false;
  }
};
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  int n, q;
  cin >> n >> q;
  vector<int> qu(q), qv(q), qx(q);
  for (int i = 0; i < q; i++) {
    cin >> qu[i] >> qv[i] >> qx[i];
    --qu[i];
    --qv[i];
  }
  DSU dsu(n);
  vector<vector<pair<int, int>>> g(n);
  vector<int> tree_edge(q);
  for (int i = 0; i < q; i++) {
    int u = qu[i], v = qv[i], x = qx[i];
    if (dsu.unite(u, v)) {
      g[u].push_back(make_pair(v, x));
      g[v].push_back(make_pair(u, x));
      tree_edge[i] = 1;
    }
  }
  vector<int> was(n);
  vector<vector<int>> parent(n, vector<int>(22, -1));
  vector<int> tin(n), tout(n);
  vector<int> who(2 * n);
  int timer = 0;
  vector<int> len(n);
  vector<int> my_root(n);
  int root = -1;
  vector<int> depth(n);
  function<void(int, int)> DFS = [&](int v, int pv) {
    was[v] = 1;
    assert(root != -1);
    my_root[v] = root;
    parent[v][0] = pv;
    tin[v] = timer;
    who[timer] = v;
    ++timer;
    for (const auto &e : g[v]) {
      int u = e.first;
      if (u == pv) {
        continue;
      }
      len[u] = len[v] ^ e.second;
      depth[u] = depth[v] + 1;
      DFS(u, v);
    }
    tout[v] = timer;
    ++timer;
  };
  for (int i = 0; i < n; i++) {
    if (!was[i]) {
      root = i;
      DFS(i, -1);
    }
  }
  segtree st(timer);
  assert(timer == 2 * n);
  for (int j = 1; j < 22; j++) {
    for (int i = 0; i < n; i++) {
      if (parent[i][j - 1] != -1) {
        parent[i][j] = parent[parent[i][j - 1]][j - 1];
      }
    }
  }
  auto Length = [&](int u, int v) { return len[u] ^ len[v]; };
  int lg = 21;
  auto LCA = [&](int x, int y) {
    if (depth[x] < depth[y]) {
      swap(x, y);
    }
    for (int i = lg; i >= 0; i--) {
      if (depth[x] - (1 << i) >= depth[y] && parent[x][i] != -1) {
        x = parent[x][i];
      }
    }
    if (x == y) {
      return x;
    }
    for (int i = lg; i >= 0; i--) {
      if (parent[x][i] != -1 && parent[y][i] != -1) {
        if (parent[x][i] != parent[y][i]) {
          x = parent[x][i];
          y = parent[y][i];
        }
      }
    }
    assert(parent[x][0] == parent[y][0]);
    return parent[x][0];
  };
  auto Used = [&](int x, int y, int lca) {
    assert(my_root[x] == my_root[y]);
    int from_x = st.get(tin[my_root[x]], tin[x]).sum;
    int from_y = st.get(tin[my_root[y]], tin[y]).sum;
    int from_lca = st.get(tin[my_root[lca]], tin[lca]).sum;
    return from_x + from_y - 2 * from_lca > 0;
  };
  for (int m = 0; m < q; m++) {
    if (!tree_edge[m]) {
      int u = qu[m], v = qv[m], x = qx[m];
      int lca = LCA(u, v);
      if ((Length(u, v) ^ x) == 1 && !Used(u, v, lca)) {
        while (u != lca) {
          st.modify(tin[u], tin[u], +1);
          st.modify(tout[u], tout[u], -1);
          u = parent[u][0];
        }
        while (v != lca) {
          st.modify(tin[v], tin[v], +1);
          st.modify(tout[v], tout[v], -1);
          v = parent[v][0];
        }
        cout << "YES" << '\n';
      } else {
        cout << "NO" << '\n';
      }
    } else {
      cout << "YES" << '\n';
    }
  }
  return 0;
}
