#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
#include <bits/stdc++.h>
#define owo(i,a, b) for(int i=(a);i<(b); ++i)
#define uwu(i,a, b) for(int i=(a)-1; i>=(b); --i)
#define senpai push_back
#define ttgl pair<int, int>
#define ayaya cout<<"ayaya~"<<endl
using namespace std;
/*#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
gpu_hash_table<pair<int, int>, int> mp;
#define ordered_set tree<ttgl, null_type,less<ttgl>, rb_tree_tag,tree_order_statistics_node_update>*/
 
using ll = long long;
using ld = long double;
const ll MOD = 998244353;
const ll root = 62;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
ll binpow(ll a,ll b){ll res=1;while(b){if(b&1)res=(res*a)%MOD;a=(a*a)%MOD;b>>=1;}return res;}
ll modInv(ll a){return binpow(a, MOD-2);}
const double PI = acos(-1);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int NINF = 0xc0c0c0c0;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const ll NINFLL = 0xc0c0c0c0c0c0c0c0;
const int mxN = 100001;
int n, m;
map<pair<int, int>, int> mp;
int type[mxN][3];
//lets store all pairs (a, a), (a-1, a), (a-2, a) as 4 different states, -1 if untouched, 0 if one is 0, 1 if one is 1, 2 if fixed both ways
int main() {
    //freopen("file.in", "r", stdin);
    //freopen("file.out", "w", stdout);
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    cin.tie(0)->sync_with_stdio(0);
    cin>>n>>m;
    ll fre = 1LL*(n-2)*(n-3)/2LL;
    int a, b, c;
    owo(i, 0, mxN) {
        type[i][0] = -1;
        type[i][1] = -1;
        type[i][2] = -1;
    }
    owo(i, 0, m) {
        cin>>a>>b>>c;
        a--; b--;
        if(a<b)swap(a, b);
        if(a>b+2) {
            if(mp.count({a, b})==0) {
                mp[{a, b}] = c;
                fre--;
            }else if(mp[{a, b}]!=c){
                cout<<"0\n";
                exit(0);
            }
        }else if(a==b+2) {
            if(type[a-1][2]==-1) type[a-1][2] = c;
            else type[a-1][2] = type[a-1][2]^c+2;
        }else if(a==b+1) {
            if(type[a][1]==-1) type[a][1] = c;
            else type[a][1] = type[a][1]^c+2;
        }else if(a==b) {
            type[a][0] = c;
        }
    }
    ll one = 0;
    ll zero = 0;
    if(type[0][0]!=1)one = 1;
    if(type[0][0]!=0)zero = 1;
    //cout<<one<<" "<<zero<<"\n";
    owo(i, 1, n) {
        //cout<<i<<" "<<type[i][2]<<" "<<type[i][0]<<" "<<type[i][1]<<"\n";
        ll xx = 1;
        ll yy = 1;
        if(type[i][2]==-1) {
            xx = 2;
            yy = 2;
        }else if(type[i][2]==3)xx = 0;
        else if(type[i][2]==2)yy = 0;
        if(type[i][0]==1)xx = 0;
        if(type[i][0]==0)yy = 0;
        ll xxx = 1;
        ll yyy = 1;
        if(type[i][1]==-1) {
            xxx = 2;
            yyy = 2;
        }else if(type[i][1]==3)xxx = 0;
        else if(type[i][1]==2)yyy = 0;
        //cout<<xx<<" "<<xxx<<" "<<yy<<" "<<yyy<<"\n";
        ll sone = (xx*(xxx*one + yyy*zero))%MOD;
        ll szero = (yy*(xxx*zero + yyy*one))%MOD;
        one = sone;
        zero = szero;
        //cout<<one<<" "<<zero<<"\n";
    }
    ll ans = one+zero;
    //cout<<ans<<"\n";
    if(ans&1) ans+=MOD;
    ans/=2;
    ans = (ans * binpow(2, fre))%MOD;
    cout<<ans<<"\n";
    return 0;
}

Measured memory_bytes: 7880