#include using namespace std; #include template struct UnionFindSumConstraints { int n; std::vector par; int group; // 根を x としたとき、A[i] = (pm[i] ? 1 : -1) x + B[i] std::vector pm; std::vector B; // unique: 一意に定まるか // X2: 一意に定まる場合、根の値の 2 倍を記録 std::vector unique; std::vector X2; UnionFindSumConstraints(int n) : n(n), group(n) { par.assign(n, -1); pm.assign(n, true); B.assign(n, T(0)); unique.assign(n, false); X2.assign(n, T(0)); } int find(int x) { if (par[x] < 0) return x; int p = par[x]; if (par[p] < 0) return p; find(par[x]); if (pm[x]) { pm[x] = pm[p]; B[x] += B[p]; } else { pm[x] = !pm[p]; B[x] -= B[p]; } par[x] = par[p]; return par[x]; } bool can_unite(int x, int y, T z) { // A[x] + A[y] == z int xp = find(x); int yp = find(y); if (xp == yp) { int p = xp; if (pm[x] != pm[y]) { return B[x] + B[y] == z; } else { if (unique[p]) { if (pm[x]) { return B[x] + B[y] + X2[p] == z; } else { return B[x] + B[y] - X2[p] == z; } } else { unique[p] = true; if (pm[x]) { X2[p] = z - B[x] - B[y]; } else { X2[p] = B[x] + B[y] - z; } return true; } } } else { if (!unique[xp] or !unique[yp]) { return true; } T x2 = (pm[x] ? X2[xp] : -X2[xp]) + B[x] * 2; T y2 = (pm[y] ? X2[yp] : -X2[yp]) + B[y] * 2; return x2 + y2 == 2 * z; } } bool unite(int x, int y, T z) { // A[x] + A[y] == z assert(can_unite(x, y, z)); int xp = find(x); int yp = find(y); if (xp == yp) { int p = xp; if (pm[x] != pm[y]) { assert(B[x] + B[y] == z); } else { if (!unique[p]) { unique[p] = true; if (pm[x]) { X2[p] = z - B[x] - B[y]; } else { X2[p] = B[x] + B[y] - z; } } } return false; } if (par[xp] > par[yp]) { std::swap(x, y); std::swap(xp, yp); } group--; par[xp] += par[yp]; par[yp] = xp; T tmp = z - B[x] - B[y]; B[yp] = pm[y] ? tmp : -tmp; pm[yp] = pm[x] ^ pm[y]; if (!unique[xp] and unique[yp]) { T tmp = X2[yp] - 2 * B[yp]; X2[xp] = (pm[yp] ? tmp : -tmp); unique[xp] = true; } return true; } bool same(int x, int y) { return find(x) == find(y); } int size(int x) { return -par[find(x)]; } std::vector roots() { std::vector ret; for (int i = 0; i < n; i++) { if (i == find(i)) ret.push_back(i); } return ret; } bool isroot(int x) { return x == find(x); } }; template struct Modint { int x; Modint() : x(0) {} Modint(int64_t y) { if (y >= 0) x = y % MOD; else x = (y % MOD + MOD) % MOD; } Modint &operator+=(const Modint &p) { x += p.x; if (x >= MOD) x -= MOD; return *this; } Modint &operator-=(const Modint &p) { x -= p.x; if (x < 0) x += MOD; return *this; } Modint &operator*=(const Modint &p) { x = int(1LL * x * p.x % MOD); return *this; } Modint &operator/=(const Modint &p) { *this *= p.inverse(); return *this; } Modint &operator%=(const Modint &p) { assert(p.x == 0); return *this; } Modint operator-() const { return Modint(-x); } Modint &operator++() { x++; if (x == MOD) x = 0; return *this; } Modint &operator--() { if (x == 0) x = MOD; x--; return *this; } Modint operator++(int) { Modint result = *this; ++*this; return result; } Modint operator--(int) { Modint result = *this; --*this; return result; } friend Modint operator+(const Modint &lhs, const Modint &rhs) { return Modint(lhs) += rhs; } friend Modint operator-(const Modint &lhs, const Modint &rhs) { return Modint(lhs) -= rhs; } friend Modint operator*(const Modint &lhs, const Modint &rhs) { return Modint(lhs) *= rhs; } friend Modint operator/(const Modint &lhs, const Modint &rhs) { return Modint(lhs) /= rhs; } friend Modint operator%(const Modint &lhs, const Modint &rhs) { assert(rhs.x == 0); return Modint(lhs); } bool operator==(const Modint &p) const { return x == p.x; } bool operator!=(const Modint &p) const { return x != p.x; } bool operator<(const Modint &rhs) const { return x < rhs.x; } bool operator<=(const Modint &rhs) const { return x <= rhs.x; } bool operator>(const Modint &rhs) const { return x > rhs.x; } bool operator>=(const Modint &rhs) const { return x >= rhs.x; } Modint inverse() const { int a = x, b = MOD, u = 1, v = 0, t; while (b > 0) { t = a / b; a -= t * b; u -= t * v; std::swap(a, b); std::swap(u, v); } return Modint(u); } Modint pow(int64_t k) const { Modint ret(1); Modint y(x); while (k > 0) { if (k & 1) ret *= y; y *= y; k >>= 1; } return ret; } friend std::ostream &operator<<(std::ostream &os, const Modint &p) { return os << p.x; } friend std::istream &operator>>(std::istream &is, Modint &p) { int64_t y; is >> y; p = Modint(y); return (is); } static int get_mod() { return MOD; } }; struct Arbitrary_Modint { int x; static int MOD; static void set_mod(int mod) { MOD = mod; } Arbitrary_Modint() : x(0) {} Arbitrary_Modint(int64_t y) { if (y >= 0) x = y % MOD; else x = (y % MOD + MOD) % MOD; } Arbitrary_Modint &operator+=(const Arbitrary_Modint &p) { x += p.x; if (x >= MOD) x -= MOD; return *this; } Arbitrary_Modint &operator-=(const Arbitrary_Modint &p) { x -= p.x; if (x < 0) x += MOD; return *this; } Arbitrary_Modint &operator*=(const Arbitrary_Modint &p) { x = int(1LL * x * p.x % MOD); return *this; } Arbitrary_Modint &operator/=(const Arbitrary_Modint &p) { *this *= p.inverse(); return *this; } Arbitrary_Modint &operator%=(const Arbitrary_Modint &p) { assert(p.x == 0); return *this; } Arbitrary_Modint operator-() const { return Arbitrary_Modint(-x); } Arbitrary_Modint &operator++() { x++; if (x == MOD) x = 0; return *this; } Arbitrary_Modint &operator--() { if (x == 0) x = MOD; x--; return *this; } Arbitrary_Modint operator++(int) { Arbitrary_Modint result = *this; ++*this; return result; } Arbitrary_Modint operator--(int) { Arbitrary_Modint result = *this; --*this; return result; } friend Arbitrary_Modint operator+(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { return Arbitrary_Modint(lhs) += rhs; } friend Arbitrary_Modint operator-(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { return Arbitrary_Modint(lhs) -= rhs; } friend Arbitrary_Modint operator*(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { return Arbitrary_Modint(lhs) *= rhs; } friend Arbitrary_Modint operator/(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { return Arbitrary_Modint(lhs) /= rhs; } friend Arbitrary_Modint operator%(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { assert(rhs.x == 0); return Arbitrary_Modint(lhs); } bool operator==(const Arbitrary_Modint &p) const { return x == p.x; } bool operator!=(const Arbitrary_Modint &p) const { return x != p.x; } bool operator<(const Arbitrary_Modint &rhs) { return x < rhs.x; } bool operator<=(const Arbitrary_Modint &rhs) { return x <= rhs.x; } bool operator>(const Arbitrary_Modint &rhs) { return x > rhs.x; } bool operator>=(const Arbitrary_Modint &rhs) { return x >= rhs.x; } Arbitrary_Modint inverse() const { int a = x, b = MOD, u = 1, v = 0, t; while (b > 0) { t = a / b; a -= t * b; u -= t * v; std::swap(a, b); std::swap(u, v); } return Arbitrary_Modint(u); } Arbitrary_Modint pow(int64_t k) const { Arbitrary_Modint ret(1); Arbitrary_Modint y(x); while (k > 0) { if (k & 1) ret *= y; y *= y; k >>= 1; } return ret; } friend std::ostream &operator<<(std::ostream &os, const Arbitrary_Modint &p) { return os << p.x; } friend std::istream &operator>>(std::istream &is, Arbitrary_Modint &p) { int64_t y; is >> y; p = Arbitrary_Modint(y); return (is); } static int get_mod() { return MOD; } }; int Arbitrary_Modint::MOD = 998244353; using modint9 = Modint<998244353>; using modint1 = Modint<1000000007>; using modint = Arbitrary_Modint; using mint = modint1; void solve() { int n, m; long long k; cin >> n >> m >> k; UnionFindSumConstraints UF(n); for (int i = 0; i < m; i++) { int x, y; long long z; cin >> x >> y >> z; x--; y--; if (!UF.can_unite(x, y, z)) { cout << 0 << endl; return; } UF.unite(x, y, z); } const long long inf = 1LL << 60; vector> plus(n, {inf, -inf}), minus(n, {inf, -inf}); for (int i = 0; i < n; i++) { int p = UF.find(i); if (UF.unique[p] and UF.X2[p] % 2 == 1) { cout << 0 << endl; return; } if (UF.pm[i]) { plus[p][0] = min(plus[p][0], UF.B[i]); plus[p][1] = max(plus[p][1], UF.B[i]); } else { minus[p][0] = min(minus[p][0], UF.B[i]); minus[p][1] = max(minus[p][1], UF.B[i]); } } auto f = [&](long long k) -> mint { mint ret = 1; for (int i = 0; i < n; i++) { if (!UF.isroot(i)) { continue; } if (UF.size(i) == 1) { ret *= k; continue; } long long lp = 1 - plus[i][0]; long long rp = k - plus[i][1]; long long lm = minus[i][1] - k; long long rm = minus[i][0] - 1; if (rp < lp or rm < lm) { return 0; } if (rp < lm or rm < lp) { return 0; } long long l = max(lp, lm); long long r = min(rp, rm); if (UF.unique[i]) { if (UF.X2[i] < 2 * l or 2 * r < UF.X2[i]) { return 0; } } else { ret *= r - l + 1; } } return ret; }; mint ans = f(k) - f(k - 1); cout << ans << endl; } int main() { cin.tie(0)->sync_with_stdio(0); // cout << fixed << setprecision(12); int t; t = 1; // cin >> t; while (t--) solve(); return 0; }