#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i,n) for(int i=0;i<n;++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
#define MAX_N 100010
#define SUBMIT

// ランダム連結グラフ作成
// n 頂点 m 辺の無向連結グラフを作成し edges に辺情報を格納する
// 作成に成功した場合は 0 を返す
// tuple は <0> from, <1> to, <2> cost の順番 (from < to && from != to)
// ノード id は [0, n)
// 辺のコストは [cost_min, cost_max) (※ 半開区間であることに注意)
// n <= 1000, m <= 499500 程度まで作成可能
// O(n^2)
int MakeConnectedGraph(mt19937& mt, vector< tuple<ll, ll, ll> >& edges,
        const ll n, const ll m, const ll cost_min, const ll cost_max) {
    if(m - 1 < n && n * (n - 1) / 2 < m) { return -1; }
    edges.clear();

    vector< vector<bool> > graph(n, vector<bool>(n, false) );   // i と j の辺があるなら true
    vector< pair<ll, ll> > pattern;                             // 辺の張り方全パターン

    // まず全ての頂点を連結にする
    vector<ll> connected;
    ll node = (mt() % (n - 1)) + 1;
    ll cost = (mt() % (cost_max - cost_min)) + cost_min;

    connected.push_back(0);
    connected.push_back(node);
    edges.push_back(make_tuple(0, node, cost));
    graph[0][node] = true;

    for(ll i = 1; i < n; ++i) {
        if(i == node) { continue; }
        // 連結済み頂点の中からひとつをランダムに選びそれに接続する
        ll to = connected[mt() % connected.size()];
        cost = (mt() % (cost_max - cost_min)) + cost_min;
        connected.push_back(i);
        edges.push_back(make_tuple(min(i, to), max(i, to), cost));
        graph[min(i, to)][max(i, to)] = true;
    }

    for(ll i = 0; i < n; ++i) {
        for(ll j = i + 1; j < n; ++j) {
            if(!graph[i][j]) { pattern.push_back(make_pair(i, j)); }
        }
    }
    shuffle(pattern.begin(), pattern.end(), mt);

    // まだ辺が引かれていない点どうしに辺を張る
    for(ll i = 0; i < (m - (n - 1)); ++i) {
        cost = (mt() % (cost_max - cost_min)) + cost_min;
        edges.push_back(make_tuple(pattern[i].first, pattern[i].second, cost));
    }
    assert(edges.size() == static_cast<size_t>(m));

    return 0;
}

bool valid(const vector<vector<pair<int,int>>>& g, long long v0){
    if(v0 <= 0) return false;
    const int n = g.size();
    vector<long long> value(n, 0);
    vector<int> visit(n, 0);
    queue<int> qu; qu.push(0);
    value[0] = v0;
    while(!qu.empty()){
        int curPos = qu.front(); qu.pop();
        if(visit[curPos]) continue;
        visit[curPos] = 1;
        for(auto next : g[curPos]){
            int nextValue = next.second - value[curPos];
            if(nextValue <= 0) return false;
            if(value[next.first] != 0 && value[next.first] != nextValue) return false;
            value[next.first] = nextValue;
            qu.push(next.first);
        }
    }
    return true;
}

// 愚直な解法
ll blute_force(ll N, ll M, const vector<ll>& U, const vector<ll>& V, const vector<ll>& S) {
    // 隣接リストの作成
    vector< vector< pair<ll, ll> > > graph(N, vector< pair<ll, ll> >());    // to, cost
    REP(i, M) {
        ll from, to, cost;
        from = U[i];
        to = V[i];
        cost = S[i];
        from--; to--;
        graph[from].push_back(make_pair(to, cost));
        graph[to].push_back(make_pair(from, cost));
    }
    const int n = graph.size();
    vector<int> sgn(n, 0);
    vector<long long> value(n, 0);
    queue<int> qu; qu.push(0);
    sgn[0] = 1;
    long long min_value = 0, max_value = 1LL << 60;
    while(!qu.empty()){
        int curPos = qu.front(); qu.pop();
        if(sgn[curPos] == 1) min_value = max(min_value, -value[curPos]);
        else max_value = min(max_value, value[curPos]);
        for(auto nextData : graph[curPos]){
            int nextPos = nextData.first;
            int nextValue = nextData.second - value[curPos];
            if(sgn[nextPos] != 0){
                if(sgn[nextPos] == sgn[curPos]){
                    long long vd = sgn[curPos] * (nextData.second - value[curPos] - value[nextPos]);
                    if(abs(vd)%2 != 0) return 0;
                    return valid(graph, vd/2) ? 1 : 0;
                } else {
                    if(nextValue != value[nextPos]) return 0;
                }
            } else {
                sgn[nextPos] = -sgn[curPos];
                value[nextPos] = nextValue;
                qu.push(nextPos);
            }
        }
    }
    return max(0LL, max_value - min_value - 1);
}

const pair<ll, bool> init_pair = make_pair(-LLINF, true);

// 始点 s の値を val としたときにグラフが成立するなら true を返す
bool check(const vector< vector< pair<ll, ll> > >& graph, ll N, ll s, ll val) {
    vector<ll> g2(N, -1);   // 各ノードに入っている値
    queue<ll> que;
    que.push(s);
    g2[s] = val;
    while(!que.empty()) {
        ll from = que.front();
        que.pop();
        for(auto& next_n : graph[from]) {
            ll to = next_n.first;
            ll cost = next_n.second;
            if(g2[to] == -1) {
                g2[to] = cost - g2[from];
                if(g2[to] <= 0) { return false; }
                que.push(to);
            } else {
                ll comp = cost - g2[from];
                if(comp != g2[to]) { return false; }
            }
        }
    }
    return true;
}

ll solve(ll N, ll M, const vector<ll>& U, const vector<ll>& V, const vector<ll>& S) {
    vector< vector< pair<ll, ll> > > graph(N, vector< pair<ll, ll> >());    // to, cost
    // 現在 i に課された条件
    // t : 始点に設定する値
    // second == bool -> (first + t) second == false -> (first - t)
    vector< pair<ll, bool> > cond(N, pair<ll, bool>());

    // 隣接リストの作成
    REP(i, M) {
        ll from, to, cost;
        from = U[i];
        to = V[i];
        cost = S[i];
        from--; to--;
        graph[from].push_back(make_pair(to, cost));
        graph[to].push_back(make_pair(from, cost));
    }
    REP(i, N) {
        cond[i] = init_pair;
    }

    // 適当な頂点を始点にして幅優先探索
    cond[0] = make_pair(0, true);  // 始まりのノードに設定する値を t と仮定
    vector<bool> isChecked(N, false);
    queue<ll> que;
    que.push(0);
    while(!que.empty()) {
        ll from = que.front();
        que.pop();
        isChecked[from] = true;
        for(auto& next_n : graph[from]) {
            ll to = next_n.first;
            ll cost = next_n.second;

            pair<ll, bool> next_cond;    // 辺の先のノードに設定したい条件
            next_cond.first = cost - cond[from].first;
            next_cond.second = !cond[from].second;
            if(cond[to] == init_pair) {
                // まだ条件が入っていない
                cond[to] = next_cond;
            }
            else {
                // すでに条件が入っている
                if(next_cond.second == cond[to].second) {
                    if(next_cond.first != cond[to].first) {
                        // パターンなし
                        return 0;
                    }
                }
                else {
                    // ノード to の値が確定する
                    ll val = (next_cond.first + cond[to].first) / 2;
                    // 確定した値でグラフがうまく回るか確認
                    if(check(graph, N, to, val)) {
                        return 1;
                    }
                    else { return 0; }
                }
            }

            if(!isChecked[to]) { que.push(to); }
        }
    }

    ll right = LLINF;
    ll left = 0;
    REP(i, N) {
        if(!cond[i].second) {
            right = min(right, cond[i].first - 1);
        }
        else {
            left = max(left, -cond[i].first);
        }
    }

    return max(0LL, right - left);
}

signed main()
{
#ifdef SUBMIT
    // 提出用コード
    ll N, M;
    cin >> N >> M;
    vector<ll> U(M, 0);
    vector<ll> V(M, 0);
    vector<ll> S(M, 0);
    REP(i, M) {
        cin >> U[i] >> V[i] >> S[i];
    }

    ll ans = solve(N, M, U, V, S);
    printf("%lld\n", ans);
#else
    // 検証用コード
    vector< tuple<ll, ll, ll> > edges;
    random_device r;
    mt19937 mt(r());
    const int loop = 100000;
    ll cnt_one = 0;
    ll cnt_zero = 0;
    REP(l, loop) {
        ll N = mt() % 20 + 2;
        uniform_int_distribution<> dist(N-1, N * (N-1) / 2);
        ll M = dist(mt);
        ll ret = MakeConnectedGraph(mt, edges, N, M, 3, 5);
        assert(ret == 0);
        vector<ll> U(M, 0);
        vector<ll> V(M, 0);
        vector<ll> S(M, 0);
        REP(i, edges.size()) {
            U[i] = get<0>(edges[i]);
            V[i] = get<1>(edges[i]);
            S[i] = get<2>(edges[i]);
            U[i]++; V[i]++;
        }
        ll cand = solve(N, M, U, V, S);
        ll ans = blute_force(N, M, U, V, S);
        if(ans == 1) { cnt_one++; }
        else if(ans == 0) { cnt_zero++; }
        if(cand != ans) {
            printf("%lld %lld\n", N, M);
            REP(i, M) {
                printf("%lld %lld %lld\n", U[i], V[i], S[i]);
            }
            printf("cand: %lld ans: %lld\n", cand, ans);
            break;
        }
    }

    printf("ans == 1: %lld ans == 0: %lld\n", cnt_one, cnt_zero);

#endif

    return 0;
}


Measured memory_bytes: 12928