#include <cassert>
#include <algorithm>
#include <cctype>
#include <complex>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <sstream>
#include <tuple>
#include <typeinfo>
#include <unordered_set>
#include <unordered_map>
#include <vector>
using namespace std;

#define REP2(i, m, n) for(int i = (int)(m); i < (int)(n); i++)
#define REPD(i, n) for(int i = (int)(n) - 1; i >= 0; i--)
#define REP(i, n) REP2(i, 0, n)
#define ALL(c) (c).begin(), (c).end()
#define PB(e) push_back(e)
#define FOREACH(i, c) for(auto i = (c).begin(); i != (c).end(); ++i)
#define MP(a, b) make_pair(a, b)
#define BIT(n, m) (((n) >> (m)) & 1)

typedef long long ll;

template <typename S, typename T> ostream &operator<<(ostream &out, const pair<S, T> &p) {
  out << "(" << p.first << ", " << p.second << ")";
  return out;
}

template <typename T> ostream &operator<<(ostream &out, const vector<T> &v) {
  out << "[";
  REP(i, v.size()){
    if (i > 0) out << ", ";
    out << v[i];
  }
  out << "]";
  return out;
}

const ll mod = 998244353;
ll modpow(ll n, ll p) {
  ll res = 1;
  while (p > 0) {
    if (p & 1) {
      res *= n;
      res %= mod;
    }
    p >>= 1;
    n *= n;
    n %= mod;
  }
  return res;
}

bool check(int a, int b, int c, unordered_map<int, unordered_map<int, int>> &color) {
  return !(color.count(a) && color[a].count(b) && color[a][b] != c);
}

int main(int argc, char *argv[])
{
  ll N, M;
  cin >> N >> M;
  vector<int> A(M), B(M), C(M);
  unordered_map<int, unordered_map<int, int>> color;

  bool ng = false;
  REP(i, M) {
    cin >> A[i] >> B[i] >> C[i];
    color[A[i]][B[i]] = C[i];
    if (abs(A[i] - B[i]) >= 3 && color[B[i]].count(A[i]) &&
        ((color[A[i]][B[i]] + color[B[i]][A[i]]) % 2 == 1)) {
      ng = true;
    }
  }

  if (ng) {
    cout << 0 << endl;
    return 0;
  }
  set<pair<int, int>> determined_far_pairs;
  REP(i, M) {
    if (abs(A[i] - B[i]) >= 3 ) {
      determined_far_pairs.insert(make_pair(min(A[i], B[i]), max(A[i], B[i])));
    }
  }
  ll res0 = modpow(2, ((N - 2) * (N - 3) / 2) - determined_far_pairs.size());
  ll dp[N][2];
  memset(dp, 0, sizeof(ll) * N * 2);

  dp[1][0] = 0;
  dp[1][1] = 0;
  REP(mask, 1 << 4) {
    int target_color = mask & 1;
    int next_color0 = (mask >> 1) & 1;
    int next_color1 = (mask >> 2) & 1;
    int next_color2 = (mask >> 3) & 1;
    if ((target_color + next_color0 + next_color1 + next_color2) % 2 != 0) {
      continue;
    }
    if (!check(2, 2, target_color, color) ||
        !check(1, 2, next_color0, color) ||
        !check(2, 1, next_color1, color) ||
        !check(1, 1, next_color2, color)) {
      continue;
    }
    dp[1][target_color]++;
  }

  for (int i = 2; i < N; i++) {
    REP(j, 2) {
      REP(mask, 1 << 5) {
        int target_color = mask & 1;
        int next_color0 = (mask >> 1) & 1;
        int next_color1 = (mask >> 2) & 1;
        int next_color2 = (mask >> 3) & 1;
        int next_color3 = (mask >> 4) & 1;

        if ((target_color + next_color0 + next_color1 + next_color2 + next_color3) % 2 != 0) {
          continue;
        }

        if ((target_color + next_color0 + next_color1 + j) % 2 != 0) {
          continue;
        }
        
        if (!check(i + 1, i + 1, target_color, color) ||
            !check(i + 0, i + 1, next_color0, color) ||
            !check(i + 1, i + 0, next_color1, color) ||
            !check(i - 1, i + 1, next_color2, color) ||
            !check(i + 1, i - 1, next_color3, color)) {
          continue;
        }
        dp[i][target_color] += dp[i - 1][j];
        dp[i][target_color] %= mod;
      }
    }
  }

  cout << res0 * (dp[N - 1][0] + dp[N - 1][1]) % mod << endl;
  return 0;
}


Measured memory_bytes: 13604