#include using namespace std; #define rep(i, n) for(int i = 0; i < n; i++) #define rep2(i, x, n) for(int i = x; i <= n; i++) #define rep3(i, x, n) for(int i = x; i >= n; i--) #define each(e, v) for(auto &e: v) #define pb push_back #define eb emplace_back #define all(x) x.begin(), x.end() #define rall(x) x.rbegin(), x.rend() #define sz(x) (int)x.size() using ll = long long; using pii = pair; using pil = pair; using pli = pair; using pll = pair; const int MOD = 1000000007; //const int MOD = 998244353; const int inf = (1<<30)-1; const ll INF = (1LL<<60)-1; template bool chmax(T &x, const T &y) {return (x < y)? (x = y, true) : false;}; template bool chmin(T &x, const T &y) {return (x > y)? (x = y, true) : false;}; struct io_setup{ io_setup(){ ios_base::sync_with_stdio(false); cin.tie(NULL); cout << fixed << setprecision(15); } } io_setup; template struct Mod_Int{ int x; Mod_Int() : x(0) {} Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {} Mod_Int &operator += (const Mod_Int &p){ if((x += p.x) >= mod) x -= mod; return *this; } Mod_Int &operator -= (const Mod_Int &p){ if((x += mod - p.x) >= mod) x -= mod; return *this; } Mod_Int &operator *= (const Mod_Int &p){ x = (int) (1LL * x * p.x % mod); return *this; } Mod_Int &operator /= (const Mod_Int &p){ *this *= p.inverse(); return *this; } Mod_Int &operator ++ () {return *this += Mod_Int(1);} Mod_Int operator ++ (int){ Mod_Int tmp = *this; ++*this; return tmp; } Mod_Int &operator -- () {return *this -= Mod_Int(1);} Mod_Int operator -- (int){ Mod_Int tmp = *this; --*this; return tmp; } Mod_Int operator - () const {return Mod_Int(-x);} Mod_Int operator + (const Mod_Int &p) const {return Mod_Int(*this) += p;} Mod_Int operator - (const Mod_Int &p) const {return Mod_Int(*this) -= p;} Mod_Int operator * (const Mod_Int &p) const {return Mod_Int(*this) *= p;} Mod_Int operator / (const Mod_Int &p) const {return Mod_Int(*this) /= p;} bool operator == (const Mod_Int &p) const {return x == p.x;} bool operator != (const Mod_Int &p) const {return x != p.x;} Mod_Int inverse() const{ assert(*this != Mod_Int(0)); return pow(mod-2); } Mod_Int pow(long long k) const{ Mod_Int now = *this, ret = 1; for(; k > 0; k >>= 1, now *= now){ if(k&1) ret *= now; } return ret; } friend ostream &operator << (ostream &os, const Mod_Int &p){ return os << p.x; } friend istream &operator >> (istream &is, Mod_Int &p){ long long a; is >> a; p = Mod_Int(a); return is; } }; using mint = Mod_Int; ll K; template struct Weighted_Graph{ struct edge{ int to; T cost; int id; edge(int to, T cost, int id) : to(to), cost(cost), id(id) {} }; vector> es; const T INF_T; const int n; int m; vector> a; vector> used; vector mi, ma; T tmp; Weighted_Graph(int n) : es(n), INF_T(numeric_limits::max()/2), n(n), m(0), a(n, vector(2, -INF_T)), used(n, vector(2, false)) {} void add_edge(int from, int to, T cost){ es[from].emplace_back(to, cost, m); if(!directed) es[to].emplace_back(from, cost, m); m++; } void dfs(int now, int col, T x){ a[now][col] = x; used[now][col] = true; chmin(mi[col], x), chmax(ma[col], x); col ^= 1; if(used[now][0] && used[now][1]){ T y = a[now][1]-a[now][0]; if(y < 0 || (y&1) || (tmp != -INF_T && tmp != y/2)){ cout << "0\n"; exit(0); } tmp = y/2; } each(e, es[now]){ if(used[e.to][col]){ if(a[e.to][col] != e.cost-x){ cout << "0\n"; exit(0); } } else{ dfs(e.to, col, e.cost-x); } } } vector ans1, ans2; //各連結成分ごとにmaxがKになるもの、全体の場合の数 void solve(){ mi.resize(2), ma.resize(2); rep(i, n){ if(used[i][0] || used[i][1]) continue; fill(all(mi), INF_T), fill(all(ma), -INF_T); tmp = -INF_T; dfs(i, 0, 0); //rep(i, 2) cout << mi[i] << ' ' << ma[i] << '\n'; //cout << tmp << '\n'; if(tmp != -INF_T){ vector check; check.eb(tmp+mi[0]), check.eb(tmp+ma[0]); check.eb(-tmp+mi[1]), check.eb(-tmp+ma[1]); bool f1 = false, f2 = false; each(e, check){ if(e <= 0 || e > K) f1 = true; if(e == K) f2 = true; } if(f1){ cout << "0\n"; exit(0); } ans1.eb(f2? 1 : 0), ans2.eb(1); } else{ T L1 = 1-mi[0], R1 = K-ma[0]; T L2 = ma[1]-K, R2 = mi[1]-1; T L = max(L1, L2), R = min(R1, R2); if(R < L){ cout << "0\n"; exit(0); } int t = 0; if(L == L2) t++; if(R == R1 && R != L) t++; ans1.eb(t), ans2.eb(R-L+1); //cout << t << ' ' << R-L+1 << '\n'; } } mint ans = 1, rem = 1; rep(i, sz(ans1)){ ans *= ans2[i], rem *= ans2[i]-ans1[i]; } cout << ans-rem << '\n'; } }; int main(){ int N, M; cin >> N >> M >> K; Weighted_Graph G(N); rep(i, M){ int u, v, w; cin >> u >> v >> w; u--, v--; G.add_edge(u, v, w); } G.solve(); }