/** * author: ivanzuki * created: Sat May 08 2021 **/ #include using namespace std; string to_string(string s) { return '"' + s + '"'; } string to_string(const char* s) { return to_string((string) s); } string to_string(bool b) { return (b ? "true" : "false"); } template string to_string(pair p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; } template string to_string(A v) { bool first = true; string res = "{"; for (const auto &x : v) { if (!first) { res += ", "; } first = false; res += to_string(x); } res += "}"; return res; } void debug_out() { cerr << endl; } template void debug_out(Head H, Tail... T) { cerr << " " << to_string(H); debug_out(T...); } template void dout(string name, int idx, T arg) { cerr << name << " = " << to_string(arg); } template void dout(string names, int idx, T1 arg, T2... args) { cerr << names.substr(0, names.find(',')) << " = " << to_string(arg) << ", "; dout(names.substr(names.find(',') + 2), idx + 1, args...); } #ifdef LOCAL #define debug(...) cerr << "[", dout(#__VA_ARGS__, 0, __VA_ARGS__), cerr << "]" << endl; #else #define debug(...) 42 #endif template T inverse(T a, T m) { T u = 0, v = 1; while (a != 0) { T t = m / a; m -= t * a; swap(a, m); u -= t * v; swap(u, v); } assert(m == 1); return u; } template class Modular { public: using Type = typename decay::type; constexpr Modular() : value() {} template Modular(const U& x) { value = normalize(x); } template static Type normalize(const U& x) { Type v; if (-mod() <= x && x < mod()) v = static_cast(x); else v = static_cast(x % mod()); if (v < 0) v += mod(); return v; } const Type& operator()() const { return value; } template explicit operator U() const { return static_cast(value); } constexpr static Type mod() { return T::value; } Modular& operator+=(const Modular& other) { if ((value += other.value) >= mod()) value -= mod(); return *this; } Modular& operator-=(const Modular& other) { if ((value -= other.value) < 0) value += mod(); return *this; } template Modular& operator+=(const U& other) { return *this += Modular(other); } template Modular& operator-=(const U& other) { return *this -= Modular(other); } Modular& operator++() { return *this += 1; } Modular& operator--() { return *this -= 1; } Modular operator++(int) { Modular result(*this); *this += 1; return result; } Modular operator--(int) { Modular result(*this); *this -= 1; return result; } Modular operator-() const { return Modular(-value); } template typename enable_if::Type, int>::value, Modular>::type& operator*=(const Modular& rhs) { #ifdef _WIN32 uint64_t x = static_cast(value) * static_cast(rhs.value); uint32_t xh = static_cast(x >> 32), xl = static_cast(x), d, m; asm( "divl %4; \n\t" : "=a" (d), "=d" (m) : "d" (xh), "a" (xl), "r" (mod()) ); value = m; #else value = normalize(static_cast(value) * static_cast(rhs.value)); #endif return *this; } template typename enable_if::Type, int64_t>::value, Modular>::type& operator*=(const Modular& rhs) { int64_t q = static_cast(static_cast(value) * rhs.value / mod()); value = normalize(value * rhs.value - q * mod()); return *this; } template typename enable_if::Type>::value, Modular>::type& operator*=(const Modular& rhs) { value = normalize(value * rhs.value); return *this; } Modular& operator/=(const Modular& other) { return *this *= Modular(inverse(other.value, mod())); } template friend const Modular& abs(const Modular& v) { return v; } template friend bool operator==(const Modular& lhs, const Modular& rhs); template friend bool operator<(const Modular& lhs, const Modular& rhs); template friend std::istream& operator>>(std::istream& stream, Modular& number); private: Type value; }; template bool operator==(const Modular& lhs, const Modular& rhs) { return lhs.value == rhs.value; } template bool operator==(const Modular& lhs, U rhs) { return lhs == Modular(rhs); } template bool operator==(U lhs, const Modular& rhs) { return Modular(lhs) == rhs; } template bool operator!=(const Modular& lhs, const Modular& rhs) { return !(lhs == rhs); } template bool operator!=(const Modular& lhs, U rhs) { return !(lhs == rhs); } template bool operator!=(U lhs, const Modular& rhs) { return !(lhs == rhs); } template bool operator<(const Modular& lhs, const Modular& rhs) { return lhs.value < rhs.value; } template Modular operator+(const Modular& lhs, const Modular& rhs) { return Modular(lhs) += rhs; } template Modular operator+(const Modular& lhs, U rhs) { return Modular(lhs) += rhs; } template Modular operator+(U lhs, const Modular& rhs) { return Modular(lhs) += rhs; } template Modular operator-(const Modular& lhs, const Modular& rhs) { return Modular(lhs) -= rhs; } template Modular operator-(const Modular& lhs, U rhs) { return Modular(lhs) -= rhs; } template Modular operator-(U lhs, const Modular& rhs) { return Modular(lhs) -= rhs; } template Modular operator*(const Modular& lhs, const Modular& rhs) { return Modular(lhs) *= rhs; } template Modular operator*(const Modular& lhs, U rhs) { return Modular(lhs) *= rhs; } template Modular operator*(U lhs, const Modular& rhs) { return Modular(lhs) *= rhs; } template Modular operator/(const Modular& lhs, const Modular& rhs) { return Modular(lhs) /= rhs; } template Modular operator/(const Modular& lhs, U rhs) { return Modular(lhs) /= rhs; } template Modular operator/(U lhs, const Modular& rhs) { return Modular(lhs) /= rhs; } template Modular power(const Modular& a, const U& b) { assert(b >= 0); Modular x = a, res = 1; U p = b; while (p > 0) { if (p & 1) res *= x; x *= x; p >>= 1; } return res; } template bool IsZero(const Modular& number) { return number() == 0; } template string to_string(const Modular& number) { return to_string(number()); } template std::ostream& operator<<(std::ostream& stream, const Modular& number) { return stream << number(); } template std::istream& operator>>(std::istream& stream, Modular& number) { typename common_type::Type, int64_t>::type x; stream >> x; number.value = Modular::normalize(x); return stream; } /* using ModType = int; struct VarMod { static ModType value; }; ModType VarMod::value; ModType& md = VarMod::value; using Mint = Modular; */ constexpr int md = (int) 1e9 + 7; using Mint = Modular::type, md>>; const int inf = (int) 1e9; int main() { ios_base::sync_with_stdio(false); cin.tie(0); int n, m, k; cin >> n >> m >> k; vector>> g(n); for (int i = 0; i < m; i++) { int x, y, z; cin >> x >> y >> z; --x; --y; g[x].emplace_back(y, z); g[y].emplace_back(x, z); } vector was(n); vector value(n, -1); vector depth(n); int cc = 0; vector can(n, 1); vector l(n, -inf), r(n, inf); vector all_ways(n), inner_ways(n); vector> needs(n); function DFS = [&](int v) { was[v] = 1; if (depth[v] % 2 == 0) { if (value[v] > k) { can[cc] = 0; } else { l[cc] = max(l[cc], -value[v] + 1); r[cc] = min(r[cc], k - value[v]); } } else { if (value[v] >= k) { l[cc] = max(l[cc], value[v] - k); } r[cc] = min(r[cc], value[v] - 1); } for (const auto& e : g[v]) { int u = e.first, w = e.second; if (was[u] == 0) { value[u] = w - value[v]; depth[u] = depth[v] + 1; DFS(u); } else { if (depth[v] % 2 == depth[u] % 2) { if (abs(w - (value[v] + value[u])) % 2 == 0) { if (depth[v] % 2 == 0) { int need = (w - (value[v] + value[u])) / 2; if (need < 0) { can[cc] = 0; } else { needs[cc].insert(need); } } else { int need = ((value[v] + value[u]) - w) / 2; if (need < 0) { can[cc] = 0; } else { needs[cc].insert(need); } } } else { can[cc] = 0; } } else { if (value[v] + value[u] != w) { can[cc] = 0; } } } } }; Mint ans = 1; vector value_k(n); vector was_k(n); function TheMax = [&](int v) { was_k[v] = 1; int ret = value_k[v]; for (const auto& e : g[v]) { int u = e.first, w = e.second; value_k[u] = w - value_k[v]; if (!was_k[u]) { ret = max(ret, TheMax(u)); } } return ret; }; for (int i = 0; i < n; i++) { if (was[i] == 0) { value[i] = 1; DFS(i); if (!can[cc]) { ans = 0; } else { auto Doable = [&](const set& needs) { int last = -1; for (const auto& t : needs) { if (t != l[cc] && t != r[cc]) { return false; } if (last != -1) { if (t != last) { return false; } } last = t; } return true; }; if (l[cc] > r[cc] || l[cc] < 0 || !Doable(needs[cc])) { can[cc] = 0; } else { value_k[i] = l[cc] + 1; // all_ways[cc] = 1 + (l[cc] < r[cc]); // debug(TheMax(i)); bool left = (TheMax(i) == k && (needs[cc].empty() || *needs[cc].begin() == l[cc])); debug(all_ways[cc]); value_k[i] = r[cc] + 1; fill(was_k.begin(), was_k.end(), 0); // debug(TheMax(i)); bool right = (l[cc] < r[cc] && TheMax(i) == k && (needs[cc].empty() || *needs[cc].begin() == r[cc])); debug(all_ways[cc]); all_ways[cc] = left + right; inner_ways[cc] = max(0, r[cc] - l[cc] - 1 + !left + !right); } ans *= (all_ways[cc] + inner_ways[cc]); } ++cc; } } if (ans == 0) { debug(ans, l, r, cc, all_ways, inner_ways, can, needs); cout << ans << '\n'; } else { Mint remove = 1; for (int i = 0; i < cc; i++) { remove *= inner_ways[i]; } debug(ans, remove, l, r, cc, all_ways, inner_ways, needs); ans -= remove; cout << ans << '\n'; } return 0; }