#include using namespace std; using ll = long long; using ld = long double; using ull = unsigned long long; #define rep(i,n) for(ll i=0;i T div_floor(T a, T b) { return a / b - ((a ^ b) < 0 && a % b); } template T div_ceil(T a, T b) { return a / b + ((a ^ b) > 0 && a % b); } template inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; } template inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; } template ostream &operator<<(ostream &os,const pair &p){ return os< ostream &operator<<(ostream &os, const vector &a){ if (a.empty()) return os; os << a.front(); for (auto e : a | views::drop(1)){ os << ' ' << e; } return os; } void dump(auto ...vs){ ((cout << vs << ' '), ...) << endl; } #ifndef LIBRARY_DATA_STRUCTURE_DSU_HPP #define LIBRARY_DATA_STRUCTURE_DSU_HPP #line 1 "src/data-structure/dsu.hpp" #include #include #include struct dsu { public: dsu() : _n(0) {} /// n 頂点の Union-Find を作る。 explicit dsu(int n) : _n(n), parent_or_size(n, -1) {} /// a と b を同じ集合にまとめ、代表元を返す。 int merge(int a, int b) { int x = leader(a), y = leader(b); if (x == y) return x; if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y); parent_or_size[x] += parent_or_size[y]; parent_or_size[y] = x; return x; } /// a と b が同じ集合なら true。 bool same(int a, int b) { return leader(a) == leader(b); } /// a が属する集合の代表元を返す。 int leader(int a) { if (parent_or_size[a] < 0) return a; return parent_or_size[a] = leader(parent_or_size[a]); } /// a が属する集合のサイズを返す。 int size(int a) { return -parent_or_size[leader(a)]; } /// 全ての連結成分を頂点リストとして返す。 std::vector> groups() { std::vector leader_buf(_n), group_size(_n); for (int i = 0; i < _n; i++) { leader_buf[i] = leader(i); group_size[leader_buf[i]]++; } std::vector> result(_n); for (int i = 0; i < _n; i++) { result[i].reserve(group_size[i]); } for (int i = 0; i < _n; i++) { result[leader_buf[i]].push_back(i); } result.erase( std::remove_if(result.begin(), result.end(), [](const std::vector& v) { return v.empty(); }), result.end()); return result; } private: int _n; // 負の値の場合:自身が根であり、その絶対値が連結成分のサイズ // 正の値の場合:親のインデックス std::vector parent_or_size; }; #endif // LIBRARY_DATA_STRUCTURE_DSU_HPP #ifndef LIBRARY_MATH_MODINT_HPP #define LIBRARY_MATH_MODINT_HPP #line 1 "src/math/modint.hpp" #include template struct static_modint { using mint = static_modint; private: int _v; public: static_modint() : _v(0) {} template static_modint(T v) { long long x = (long long)(v % MOD); if (x < 0) x += MOD; _v = int(x); } /// 0 以上 mod 未満の整数値を返す。 int val() const { return _v; } /// 法 MOD を返す。 static constexpr int mod() { return MOD; } /// 0 <= v < mod を満たす値を、剰余を取らずに構築する。 static mint raw(int v) { mint res; res._v = v; return res; } /// n 乗を返す。n >= 0。 mint pow(long long n) const { mint res(1), mul(*this); while (n > 0) { if (n & 1) res *= mul; mul *= mul; n >>= 1; } return res; } /// 逆元を返す。MOD は素数で、値は 0 でないこと。 mint inv() const { return pow(MOD - 2); } mint& operator+=(const mint& a) { _v += a._v; if (_v >= MOD) _v -= MOD; return *this; } mint& operator-=(const mint& a) { _v -= a._v; if (_v < 0) _v += MOD; return *this; } mint& operator*=(const mint& a) { _v = int((long long)_v * a._v % MOD); return *this; } mint& operator/=(const mint& a) { return *this *= a.inv(); } mint operator+() const { return *this; } mint operator-() const { return mint(0) - *this; } friend mint operator+(const mint& a, const mint& b) { return mint(a) += b; } friend mint operator-(const mint& a, const mint& b) { return mint(a) -= b; } friend mint operator*(const mint& a, const mint& b) { return mint(a) *= b; } friend mint operator/(const mint& a, const mint& b) { return mint(a) /= b; } friend bool operator==(const mint& a, const mint& b) { return a._v == b._v; } friend bool operator!=(const mint& a, const mint& b) { return a._v != b._v; } friend std::ostream& operator<<(std::ostream& os, const mint& a) { return os << a._v; } friend std::istream& operator>>(std::istream& is, mint& a) { long long v; is >> v; a = mint(v); return is; } }; using modint998244353 = static_modint<998244353>; using modint1000000007 = static_modint<1000000007>; using mint = modint998244353; #endif // LIBRARY_MATH_MODINT_HPP void solve() { ll N,Q; cin>>N>>Q; dsu uf(2*N); rep(i,Q){ ll t,a,b; cin>>t>>a>>b; a--; b--; if (t==0){ if (uf.same(a,b+N)){ cout<<0<<'\n'; return; } uf.merge(a,b); uf.merge(a+N,b+N); } else{ if (uf.same(a,b)){ cout<<0<<'\n'; return; } uf.merge(a,b+N); uf.merge(a+N,b); } } ll g=uf.groups().size(); mint ans=mint(2).pow(g/2); cout<sync_with_stdio(0); ll T=1; while (T--){ solve(); } return 0; }