Language: C++

// #includes {{{
#include<vector>
#include<unordered_map>
#include<iostream>
#include<cassert>

using namespace std;

#define REP(i,n) for(int i=0;i<(int)(n);++i)
#define RREP(i,a,b) for(int i=(int)(a);i<(int)(b);++i)
#define FOR(i,c) for(__typeof((c).begin()) i=(c).begin();i!=(c).end();++i)
#define LET(x,a) __typeof(a) x(a)
//#define IFOR(i,it,c) for(__typeof((c).begin())it=(c).begin();it!=(c).end();++it,++i)
#define ALL(c) (c).begin(), (c).end()
#define MP make_pair

#define EXIST(e,s) ((s).find(e)!=(s).end())

#define RESET(a) memset((a),0,sizeof(a))
#define SET(a) memset((a),-1,sizeof(a))
#define PB push_back
#define DEC(it,command) __typeof(command) it=command

//debug
#define dump(x)  cerr << #x << " = " << (x) << endl;
#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl;
#define debug_v(x) cerr << #x << " = [";REP(__ind,(x).size()){cerr << (x)[__ind] << ", ";}cerr << "] (L" << __LINE__ << ")" << endl;

#define whole(f,x,...) ([&](decltype((x)) whole) { return (f)(begin(whole), end(whole), ## __VA_ARGS__); })(x)

typedef long long Int;
typedef unsigned long long uInt;
typedef long double rn;

template<class T>
T inf(){
	return numeric_limits<T>::has_infinity?numeric_limits<T>::infinity():(numeric_limits<T>::max()/2);
}

typedef pair<int,int> pii;

/*
#ifdef MYDEBUG
#include"debug.h"
#include"print.h"
#endif
*/
// }}}

const int MOD = 998244353;
//{{{ modular algebra
template<int mod=MOD>
struct Num{
	int v;
	Num(int n):v(n){}
	Num():v(0){}
	operator int() const {return v;}
	operator long long() const {return v;}
	template<class T>
	Num operator =(int n){v=n;return *this;}

	template<class T>
	inline void operator *=(const T &a) {
		v = (v*(long long)a)%mod;
	}
	template<class T>
	inline Num operator *(const T &a) {
		Num n(*this);n*=a;
		return n;
	}
	template<class T>
	inline void operator+=(const T &a){
		v+=(int)a;
		if(v>=mod)v-=mod;
		//	assert(0<=v and v<mod);
	}
	template<class T>
	inline Num operator+(const T &a){
		Num n(*this);n+=a;
		return n;
	}
	inline Num operator -(){
		if(v==0)return 0;
		else return Num(mod-v);
	}
	template<class T>
	inline void operator -=(const T &a){
		v-=(int)a;
		if(v<0)v+=mod;
	}
	template<class T>
	inline Num operator -(const T &a){
		Num n(*this);n-=a;
		return n;
	}
#ifdef __GCD_H
	inline Num inv(){
		return Num(invMod(this->v,mod));
	}
	template<class T>
	inline void operator /=(const T &a){
		(*this)*=invMod((int)a,mod);
	}
	template<class T>
	inline Num operator /(const T &a){
		Num n(*this);n/=a;
		return n;
	}
#endif
};

template<class T, int mod>
T& operator <<(T &os, const Num<mod> &n){
	os<<(int)n.v;
	return os;
}

template<class T, int mod>
T& operator >>(T &is, Num<mod> &n){
	is>>n.v;
	return is;
}
//}}}
typedef Num<MOD> mod_int;

//{{{ pow
/* (x^k)%m */
template<int mod=MOD>
inline Num<mod> mod_pow(Num<mod> x, Int k){
	if(k==0) return 1;
	Num<mod> res(mod_pow(x,k/2));
	res*=res;
	if(k%2)res*=x;
	return res;
}
//}}}

namespace std {
	template <>
	class hash<std::pair<int, int>> {
	public:
		size_t operator()(const std::pair<int, int>& x) const{
			return hash<int>()(x.first) * hash<int>()(x.second);
		}
	};
}

Int M;
Int N;
vector<int> a;
vector<int> b;
vector<int> c;
unordered_map<pii,int> mp(1000000);

void solve(){
	Int num_diag = 0, num_pair = 0;
	vector<int> diag(N,-1), diag_sum(N-1,-1);
	bool valid = true;
	REP(i,M)mp[make_pair(a[i],b[i])] = c[i];
	REP(i,M){
		if(a[i]<=b[i]){
			int d = abs(a[i]-b[i]);
			if(d==0){
				diag[a[i]] = c[i];
				num_diag++;
			}else{
				auto it = mp.find(make_pair(b[i],a[i]));
				if(it==mp.end())continue;
				num_pair++;
				int c2 = it->second, sum = (c[i] + c2)%2;
				if(d==1){
					int &t = diag_sum[a[i]];
					if(t!=-1 and t!=sum){
						valid = false;
						goto L2;
					}
					t = sum;
				}else if(d==2){
					int &t = diag[a[i]+1];
					if(t!=-1 and t!=sum){
						valid = false;
						goto L2;
					}
					t = sum;
				}else{
					if(sum!=0){
						valid = false;
						goto L2;
					}
				}
			}
		}
	}
L2:
	if(!valid){
		cout<<0<<endl;
		return;
	}
	Int elem = 0;
	for(int i=0;i<N;){
		if(i<N-1 and diag_sum[i]!=-1){
			int j = i;
			while(j<N-1 and diag_sum[j]!=-1)j++;
			int val = diag[i];
			for(int k=i;k<=j;k++){
				if(diag[k]!=-1){
					if(val!=-1){
						if(diag[k]!=val){
							valid = false;
							goto L;
						}
					}else{
						val = diag[k];
					}
				}
				if(k==j)break;
				if(val!=-1)val = (val+diag_sum[k])%2;
			}
			if(val==-1)elem++;
			i = j + 1;
		}else{
			if(diag[i]==-1){
				elem++;
			}
			i++;
		}
	}
L:
	if(!valid){
		cout<<0<<endl;
		return;
	}

	Int rest = M - num_diag - num_pair*2;
	Int t = (N * N - N - num_pair*2 - rest*2)/2;
	int result = (int)(mod_pow(mod_int(2),elem+t));
	assert(0<=result and result<MOD);
	cout<<result<<endl;
}

//{{{ main function
int main(){	


	cin>>N>>M;
	a.assign(M-1+1,int());
	b.assign(M-1+1,int());
	c.assign(M-1+1,int());
	REP(i,M){
		cin >> a[i];
		cin >> b[i];
		cin >> c[i];
		a[i]--;b[i]--;
	}
	solve();
	return 0;
}
//}}}


Compiler output:
a.cc: In function 'T inf()':
a.cc:37:16: error: 'numeric_limits' was not declared in this scope
   37 |         return numeric_limits<T>::has_infinity?numeric_limits<T>::infinity():(numeric_limits<T>::max()/2);
      |                ^~~~~~~~~~~~~~
a.cc:37:32: error: expected primary-expression before '>' token
   37 |         return numeric_limits<T>::has_infinity?numeric_limits<T>::infinity():(numeric_limits<T>::max()/2);
      |                                ^
a.cc:37:35: error: '::has_infinity' has not been declared
   37 |         return numeric_limits<T>::has_infinity?numeric_limits<T>::infinity():(numeric_limits<T>::max()/2);
      |                                   ^~~~~~~~~~~~
a.cc:37:64: error: expected primary-expression before '>' token
   37 |         return numeric_limits<T>::has_infinity?numeric_limits<T>::infinity():(numeric_limits<T>::max()/2);
      |                                                                ^
a.cc:37:67: error: '::infinity' has not been declared
   37 |         return numeric_limits<T>::has_infinity?numeric_limits<T>::infinity():(numeric_limits<T>::max()/2);
      |                                                                   ^~~~~~~~
a.cc:37:95: error: expected primary-expression before '>' token
   37 |         return numeric_limits<T>::has_infinity?numeric_limits<T>::infinity():(numeric_limits<T>::max()/2);
      |                                                                                               ^
a.cc:37:101: error: no matching function for call to 'max()'
   37 |         return numeric_limits<T>::has_infinity?numeric_limits<T>::infinity():(numeric_limits<T>::max()/2);
      |                                                                                                ~~~~~^~
In file included from /usr/include/c++/14/vector:62,
                 from a.cc:2:
/usr/include/c++/14/bits/stl_algobase.h:257:5: note: candidate: 'template<class _Tp> constexpr const _Tp& std::max(const _Tp&, const _Tp&)'
  257 |     max(const _Tp& __a, const _Tp& __b)
      |     ^~~
/usr/include/c++/14/bits/stl_algobase.h:257:5: note:   candidate expects 2 arguments, 0 provided
/usr/include/c++/14/bits/stl_algobase.h:303:5: note: candidate: 'template<class _Tp, class _Compare> constexpr const _Tp& std::max(const _Tp&, const _Tp&, _Compare)'
  303 |     max(const _Tp& __a, const _Tp& __b, _Compare __comp)
      |     ^~~
/usr/include/c++/14/bits/stl_algobase.h:303:5: note:   candidate expects 3 arguments, 0 provided