Problem:
Problem F:
Slim Span
Given an undirected weighted graph
G
, you should find one of spanning trees specified as follows.
The graph
G
is an ordered pair (
V
,
E
), where
V
is a set of vertices {
v
1
,
v
2
, ... ,
v
n
} and
E
is a set of undirected edges {
e
1
,
e
2
, ... ,
e
m
}. Each edge
e
∈
E
has its weight
w
(
e
).
A spanning tree
T
is a tree (a connected subgraph without cycles) which connects all the n
vertices with
n
- 1 edges. The
slimness
of a spanning tree
T
is defined as the difference between
the largest weight and the smallest weight among the
n
- 1 edges of
T
.
Figure 5: A graph
G
and the weights of the edges
For example, a graph
G
in Figure 5(a) has four vertices {
v
1
,
v
2
,
v
3
,
v
4
} and five undirected edges {
e
1
,
e
2
,
e
3
,
e
4
,
e
5
}. The weights of the edges are
w
(
e
1
) = 3,
w
(
e
2
) = 5,
w
(
e
3
) = 6,
w
(
e
4
) = 6,
w
(
e
5
) = 7 as shown in Figure 5(b).
Figure 6: Examples of the spanning trees of
G
There are several spanning trees for
G
. Four of them are depicted in Figure 6(a)-(d). The spanning tree
T
a
in Figure 6(a) has three edges whose weights are 3, 6 and 7. The largest weight
is 7 and the smallest weight is 3 so that the slimness of the tree
T
a
is 4. The slimnesses of
spanning trees
T
b
,
T
c
and
T
d
shown in Figure 6(b), (c) and (d) are 3, 2 and 1, respectively. You
can easily see the slimness of any other spanning tree is greater than or equal to 1, thus the
spanning tree
T
d
in Figure 6(d) is one of the slimmest spanning trees whose slimness is 1.
Your job is to write a program that computes the smallest slimness.
Input
The input consists of multiple datasets, followed by a line containing two zeros separated by a space. Each dataset has the following format.
n     m
a
1
b
1
w
1
.
  .
  .
a
m
b
m
w
m
Every input item in a dataset is a non-negative integer. Items in a line are separated by a space.
n
is the number of the vertices and m the number of the edges. You can assume 2 ≤
n
≤ 100 and 0 ≤
m
≤
n
(
n
- 1)/2.
a
k
and
b
k
(
k
= 1, ... ,
m
) are positive integers less than or equal to
n
, which represent the two vertices
v
a
k
and
v
b
k
connected by the
k
th edge
e
k
.
w
k
is a positive integer less than or equal to 10000, which indicates the weight of
e
k
. You can assume that the graph
G
= (
V
,
E
) is simple, that is, there are no self-loops (that connect the same vertex) nor parallel edges (that are two or more edges whose both ends are the same two vertices).
Output
For each dataset, if the graph has spanning trees, the smallest slimness among them should be
printed. Otherwise,
-1
should be printed. An output should not contain extra characters.
Sample Input
4 5
1 2 3
1 3 5
1 4 6
2 4 6
3 4 7
4 6
1 2 10
1 3 100
1 4 90
2 3 20
2 4 80
3 4 40
2 1
1 2 1
3 0
3 1
1 2 1
3 3
1 2 2
2 3 5
1 3 6
5 10
1 2 110
1 3 120
1 4 130
1 5 120
2 3 110
2 4 120
2 5 130
3 4 120
3 5 110
4 5 120
5 10
1 2 9384
1 3 887
1 4 2778
1 5 6916
2 3 7794
2 4 8336
2 5 5387
3 4 493
3 5 6650
4 5 1422
5 8
1 2 1
2 3 100
3 4 100
4 5 100
1 5 50

...(truncated)

Submitted solutions:

code_snippet: #include <iostream>
#include <vector>
#include <tuple>
#include <algorithm>
using namespace std;

class unionfind{
public:
    unionfind(int n): n_(n), m_(n) {
        parent_.resize(n);
        size_.resize(n);
        for(int i=0; i<n; i++){
            parent_[i] = i;
            size_[i] = 1;
        }
    }
    void unite(int i, int j){
        int p = root(i);
        int q = root(j);
        if(p==q) return;
        if(size_[p]>size_[q]){
            parent_[q] = p;
            size_[p] += size_[q];
        }else{
            parent_[p] = q;
            size_[q] += size_[p];
        }
        m_ -= 1;
    }
    bool is_same(int i, int j){
        return root(i) == root(j);
    }
    int group_num(){
        return m_;
    }
private:
    int n_;
    int m_; // 連結成分数
    vector<int> parent_;
    vector<int> size_;

    int root(int i){
        if(parent_[i] == i) return i;
        parent_[i] = root(parent_[i]);
        return parent_[i];
    }
};

// 辺は(重み, 頂点1, 頂点2) (無向)
// 使った辺の重みの最大値を返す
// 全域木ができなければ代わりに-1を返す
int kruskal(int n, vector<tuple<int,int,int>> edges){
    // sort(edges.begin(), edges.end());    // ソート済み配列を渡す
    unionfind uf(n+1);  // 1-indexed
    int max_w = 0;
    // vector<pair<int,int>> mst(n-1);
    for(int i=0; i<edges.size(); i++){
        auto [w,u,v] = edges[i];
        if(!uf.is_same(u,v)){
            uf.unite(u,v);
            max_w = w;
            // mst.append(make_pair(u,v));
        }
    }
    if(uf.group_num() != 2){
        max_w = -1;
    }
    return max_w;
}

int solve(int n, vector<tuple<int,int,int>> edges){
    sort(edges.begin(), edges.end());
    int ans = -1;
    int m = edges.size();
    for(int i=0; i<m; i++){
        // その時点での最小全域木を構成
        int tmp = kruskal(n,edges);
        // 全域木ができなければその時点で終了
        if(tmp == -1){
            break;
        }
        // slimnessを記録
        if(ans == -1){
            ans = tmp - get<0>(edges[0]);
        }else{
            ans = min(ans, tmp - get<0>(edges[0]));
        }
        // 最小の辺を削除して再度実行
        edges.erase(edges.begin());
    }
    return ans;
}

int main(){
    int n,m;
    while(true){
        cin >> n >> m;
        if((n==0) & (m==0)){
            break;
        }

        vector<tuple<int,int,int>> edges;
        int x,y,w;
        for(int i=0; i<m; i++){
            cin >> x >> y >> w;
            edges.push_back({w,x,y});
        }

        cout << solve(n,edges) << endl;
    }
}
accuracy: 1
time_ms: 120
memory_kb: 3392
final_rank: 2

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <iomanip>

using namespace std;

typedef long long LL;

#define REP(i, n) for (int i(0); i < (int) (n); i++)

const int N = 100 + 10;
const int INF = (int)1e9;

int n, m;
int maxv;
int from, to;
int w[N][N];
int vis[N];
vector<int> adj[N];
pair<int, pair<int, int> > e[N * N];

bool findIt(int u, int g)
{
	if (vis[u]) return false;
	vis[u] = true;
	if (u == g) return true;
	for(int e = 0; e < (int)adj[u].size(); ++ e) {
		int v = adj[u][e];
		if (findIt(v, g)) {
			if (maxv < w[u][v]) {
				maxv = w[u][v];
				from = u;
				to = v;
			}
			return true;
		}
	}
	return false;
}

void solve() {
	for(int i = 0; i < m; ++ i) {
		int u, v, l;
		scanf("%d%d%d", &u, &v, &l);
		--u, --v;
		e[i] = make_pair(l, make_pair(u, v));
		w[u][v] = w[v][u] = l;
	}
	sort(e, e + m);

	for(int i = 0; i < n; ++ i) {
		adj[i].clear();
	}
	int ret = INF;
	vector<int> ss;
	for(int i = m - 1; i >= 0; -- i) {
		fill(vis, vis + n, false);
		maxv = -INF;
		findIt(e[i].second.first, e[i].second.second);
		if (maxv != -INF) {
			for(int j = 0; j < (int)ss.size(); ++ j) {
				if (ss[j] == maxv) {
					ss.erase(ss.begin() + j);
					break;
				}
			}
			for(int j = 0; j < adj[from].size(); ++ j) {
				if (adj[from][j] == to) {
					adj[from].erase(adj[from].begin() + j);
					break;
				}
			}
			for(int j = 0; j < adj[to].size(); ++ j) {
				if (adj[to][j] == from) {
					adj[to].erase(adj[to].begin() + j);
					break;
				}
			}
		}
		adj[e[i].second.first].push_back(e[i].second.second);
		adj[e[i].second.second].push_back(e[i].second.first);
		ss.push_back(e[i].first);
		if ((int)ss.size() == n - 1) {
			ret = min(ret, *max_element(ss.begin(), ss.end()) - *min_element(ss.begin(), ss.end()));
		}
	}
	if (ret == INF) {
		cout << -1 << endl;
		return;
	}
	cout << ret << endl;
}

int main() {
	for( ; cin >> n >> m; ) {
		if (n == 0 && m == 0) break;
		solve();
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3564
final_rank: 10

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

struct UnionFind{
    vector<int> par; int n;
    UnionFind(){}
    UnionFind(int _n):par(_n,-1),n(_n){}
    int root(int x){return par[x]<0?x:par[x]=root(par[x]);}
    bool same(int x,int y){return root(x)==root(y);}
    int size(int x){return -par[root(x)];}
    bool unite(int x,int y){
        x=root(x),y=root(y); if(x==y)return false;
        if(size(x)>size(y))swap(x,y);
        par[y]+=par[x]; par[x]=y; n--; return true;
    }
};

/**
 * @brief Union Find
 */

struct Edge {
    int A, B, C;
};

int main() {
while(1) {
    int N, M;
    cin >> N >> M;
    if (N == 0) return 0;
    vector<Edge> G(M);
    rep(i,0,M) cin >> G[i].A >> G[i].B >> G[i].C, G[i].A--, G[i].B--;
    sort(ALL(G),[](const Edge& E1, const Edge& E2){return E1.C < E2.C;});
    int ANS = inf;
    rep(i,0,M) {
        UnionFind UF(N);
        int COUNT = 0;
        rep(j,i,M) {
            if (!UF.same(G[j].A,G[j].B)) {
                UF.unite(G[j].A,G[j].B);
                COUNT++;
            }
            if (COUNT == N-1) {
                chmin(ANS,G[j].C-G[i].C);
                break;
            }
        }
    }
    cout << (ANS == inf ? -1 : ANS) << endl;
}
}
accuracy: 1
time_ms: 20
memory_kb: 3476
final_rank: 6

code_snippet: #include <bits/stdc++.h>

using ll = long long;

#define rep(i, l, r) for (ll i = (l); i < (r); i++)
#define rrep(i, r, l) for (ll i = (r); i-- > (l);)
template <class T, class U>
bool chmin(T& lhs, U rhs) {
    return lhs > rhs ? (lhs = rhs, true) : false;
}
template <class T, class U>
bool chmax(T& lhs, U rhs) {
    return lhs < rhs ? (lhs = rhs, true) : false;
}
using namespace std;

struct UF {
    vector<int> data;
    UF(int n): data(n, -1) {}
    int find(int x) {
        if (data[x] < 0) return x;
        return data[x] = find(data[x]);
    }
    bool merge(int lhs, int rhs) {
        lhs = find(lhs);
        rhs = find(rhs);
        if (lhs == rhs) return false;
        if (data[lhs] < data[rhs]) swap(lhs, rhs);
        data[rhs] += data[lhs];
        data[lhs] = rhs;
        return true;
    }
};

int solve() {
    int n, m;
    cin >> n >> m;
    if (n == 0) return 1;
    vector<tuple<int, int, int>> edges;
    UF check(n);
    int count = 0;
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        u--;
        v--;
        edges.emplace_back(w, u, v);
        count += check.merge(u, v);
    }
    sort(edges.begin(), edges.end());
    if (count != n - 1) {
        cout << -1 << '\n';
        return 0;
    }
    const int INF = 1e9;
    int ans = INF;
    rep(i, 0, m) {
        UF uf(n);
        int count = 0;
        int min_w = INF;
        int max_w = -INF;
        rep(j, i, m) {
            auto [w, u, v] = edges[j];
            if (uf.merge(u, v)) {
                count++;
                chmin(min_w, w);
                chmax(max_w, w);
            }
        }
        if (count == n - 1) chmin(ans, max_w - min_w);
    }
    cout << ans << '\n';
    return 0;
}

int main() {
    while (!solve())
        ;
}
accuracy: 1
time_ms: 80
memory_kb: 3476
final_rank: 8

code_snippet: #include <bits/stdc++.h>

using ll = long long;

#define rep(i, l, r) for (ll i = (l); i < (r); i++)
#define rrep(i, r, l) for (ll i = (r); i-- > (l);)
template <class T, class U>
bool chmin(T& lhs, U rhs) {
    return lhs > rhs ? (lhs = rhs, true) : false;
}
template <class T, class U>
bool chmax(T& lhs, U rhs) {
    return lhs < rhs ? (lhs = rhs, true) : false;
}
using namespace std;

struct UF {
    vector<int> data;
    UF(int n): data(n, -1) {}
    int find(int x) {
        if (data[x] < 0) return x;
        return data[x] = find(data[x]);
    }
    bool merge(int lhs, int rhs) {
        lhs = find(lhs);
        rhs = find(rhs);
        if (lhs == rhs) return false;
        if (data[lhs] < data[rhs]) swap(lhs, rhs);
        data[rhs] += data[lhs];
        data[lhs] = rhs;
        return true;
    }
};

int solve() {
    int n, m;
    std::cin >> n >> m;
    if (n == 0) return 1;
    const int W = 10005;
    std::vector<std::vector<std::pair<int, int>>> edges(W);
    UF check(n);
    int count = 0;
    for (int i = 0; i < m; i++) {
        int u, v, w;
        std::cin >> u >> v >> w;
        u--;
        v--;
        edges[w].emplace_back(u, v);
        count += check.merge(u, v);
    }
    if (count != n - 1) {
        std::cout << -1 << '\n';
        return 0;
    }

    auto satisfy = [&](int key) {
        for (int i = 0; i + key < W; i++) {
            UF uf(n);
            int count = 0;
            for (int w = i; w <= i + key; w++) {
                for (auto [u, v]: edges[w]) {
                    count += uf.merge(u, v);
                }
                if (count == n - 1) break;
            }
            if (count == n - 1) {
                return true;
            }
        }
        return false;
    };

    int ok = W;
    int ng = -1;
    while (ok - ng > 1) {
        int key = (ok + ng) / 2;
        (satisfy(key) ? ok : ng) = key;
    }
    std::cout << ok << '\n';
    return 0;
}

int main() {
    while (!solve())
        ;
}
accuracy: 1
time_ms: 2150
memory_kb: 3544
final_rank: 20

code_snippet: #include "bits/stdc++.h"

using namespace std;

using i64 = long long;

struct UnionFind{
    vector<int> par;
    UnionFind(int n) : par(n, -1){}
    int Find(int x){return par[x] < 0 ? x : Find(par[x]);}
    int cnt = 0;
    void Unite(int x, int y){
        x = Find(x), y = Find(y);
        if(x == y)return;//continue;
        if(par[x] > par[y]){ // if size x < size y
            swap(x, y);
        }
        par[x] += par[y];
        par[y] = x;
        ++cnt;
    }
};

int main() {
    while(true){
        int n, m;
        cin >> n >> m;
        if(n == 0)break;
        vector<int> a(m), b(m), w(m);
        for(int i = 0; i < m; ++i){
            cin >> a[i] >> b[i] >> w[i];
            --a[i], --b[i];
        }
        vector<pair<int,int>> edges;
        for(int i = 0; i < m; ++i){
            edges.emplace_back(w[i], i);
        }
        sort(edges.begin(), edges.end());
        int ans = 1e9;
        for(int i = 0; i < m; ++i){
            UnionFind uf(n);
            for(int j = i; j < m; ++j){
                int x = a[edges[j].second];
                int y = b[edges[j].second];
                uf.Unite(x, y);
                if(uf.cnt == n - 1){
                    ans = min(ans, edges[j].first - edges[i].first);
                    break;
                }
            }
        }
        cout << (ans == 1e9 ? -1 : ans) << endl;
    }

}
accuracy: 1
time_ms: 20
memory_kb: 3304
final_rank: 1

code_snippet: #include <bits/stdc++.h>

struct UnionFind {
    int n;
    std::vector<int> data;
    UnionFind(int n): data(n, -1) {}

    int find(int x) {
        if (data[x] < 0) return x;
        return data[x] = find(data[x]);
    }

    bool merge(int lhs, int rhs) {
        lhs = find(lhs);
        rhs = find(rhs);
        if (lhs == rhs) return false;
        if (data[lhs] < data[rhs]) std::swap(lhs, rhs);
        data[rhs] += data[lhs];
        data[lhs] = rhs;
        return true;
    }

    int size(int x) {
        return -data[find(x)];
    }
};

int main() {
    while (true) {
        int n, m;
        std::cin >> n >> m;
        if (n == 0 && m == 0) break;
        
        std::vector<std::tuple<int, int, int>> edges;
        edges.reserve(m);
        for (int i = 0; i < m; i++) {
            int u, v, w;
            std::cin >> u >> v >> w;
            u--; v--;
            edges.emplace_back(w, u, v);
        }
        std::sort(edges.begin(), edges.end());

        const int INF = 1e9;
        int ans = INF;
        auto solve = [&](int left) -> int {
            UnionFind uf(n);
            for (int i = left; i < m; i++) {
                auto [w, u, v] = edges[i];
                uf.merge(u, v);
                if (uf.size(0) == n) {
                    return w - std::get<0>(edges[left]);
                }
            }
            return INF;
        };

        for (int i = 0; i < m; i++) {
            int res = solve(i);
            if (res == INF) {
                break;
            }
            ans = std::min(ans, res);
        }

        if (ans == INF) ans = -1;
        std::cout << ans << std::endl;
    }
}
accuracy: 1
time_ms: 20
memory_kb: 3452
final_rank: 4

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using H = pair<ll, ll>;
using P = pair<ll, H>;
using vi = vector<int>;
using vl = vector<ll>;
#define all(a) (a).begin(), (a).end()
#define fs first
#define sc second
#define xx first
#define yy second.first
#define zz second.second
#define Q(i, j, k) mkp((i), mkp((j), (k)))
#define rng(i, s, n) for(int i = (s) ; i < (n) ; i++)
#define rep(i, n) rng(i, 0, (n))
#define mkp make_pair
#define vec vector
#define pb emplace_back
#define siz(a) int((a).size())
#define crdcomp(b) sort(all((b))); (b).erase(unique(all((b))), (b).end())
#define getidx(b, i) (lower_bound(all((b)), (i))-(b).begin())
#define ssp(i, n) (i==(ll)(n)-1?"\n":" ")
#define ctoi(c) (int)((c)-'0')
#define itoc(c) (char)((c)+'0')
#define cyes printf("Yes\n")
#define cno printf("No\n")
#define cdf(n) for(int __quetimes=(n); __quetimes>0; __quetimes--)
#define gcj printf("Case #%lld: ", __quetimes+1)
#define readv(a, n) (a).resize((n), 0); rep(i, (n)) (a)[i]=read()
#define found(a, x) (a.find(x)!=a.end())
constexpr ll mod = (ll)1e9 + 7;
constexpr ll Mod = 998244353;
constexpr ld EPS = 1e-10;
constexpr ll inf = (ll)3 * 1e18;
constexpr int Inf = 1e9;
constexpr int dx[] = { -1, 1, 0, 0 }, dy[] = { 0, 0, -1, 1 };
template<class T>bool chmax(T& a, const T& b) { if (a < b) { a = b; return 1; } return 0; }
template<class T>bool chmin(T& a, const T& b) { if (b < a) { a = b; return 1; } return 0; }
ll read() { ll u, k = scanf("%lld", &u); return u; }
string reads() { string s; cin >> s; return s; }
bool ina(H t, int h, int w) { return 0 <= t.fs && t.fs < h && 0 <= t.sc && t.sc < w; }
bool ina(int t, int l, int r) { return l <= t && t < r; }
ll gcd(ll i, ll j) { return j ? gcd(j, i % j) : i; }
template<typename T>
void fin(T x) { cout << x << endl; exit(0); }
//--------------------------------------------------------------
class unionfind {
    int size = 0, grps = 0;
    vector<int>pa;
public:
    unionfind() {}
    unionfind(int n) {
        init(n);
    }
    void init(int n) {
        size = n, grps = n;
        pa.assign(n, -1);
    }
    int root(int x) {
        if (pa[x] < 0) return x;
        return pa[x] = root(pa[x]);
    }
    bool unite(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) return false;
        grps--;
        if (pa[x] > pa[y]) swap(x, y);
        pa[x] += pa[y];
        pa[y] = x;
        return true;
    }
    bool same(int x, int y) {
        return root(x) == root(y);
    }
    bool isroot(int x) {
        return x == root(x);
    }
    int sz(int x) {
        return -pa[root(x)];
    }
    int groups() {
        return grps;
    }
    H operator[](int x) {
        x = root(x);
        return H{ x,-pa[x] };
    }
};

signed main() {
    int n, m;
    while (cin >> n >> m && n + m > 0) {
        struct edge {
            int x, y, w;
        };
        vec<edge>e(m);
        rep(i, m) cin >> e[i].x >> e[i].y >> e[i].w, e[i].x--, e[i].y--;
        sort(all(e), [&](edge& a, edge& b) {return a.w < b.w;});
        unionfind uf(n);
        int ans = Inf;
        rep(i, m) {
            uf.init(n);
            for (int j = i;j < m;j++) {
                uf.unite(e[j].x, e[j].y);
                if (uf.groups() == 1) chmin(ans, e[j].w - e[i].w);
            }
        }
        if (ans == Inf) ans = -1;
        cout << ans << endl;
    }
}
accuracy: 1
time_ms: 100
memory_kb: 3556
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
// typedef __int128 ll;
typedef double ld;
const int mod = 1e9 + 7;
const int MAXN = 18;

ll pmod(ll v, ll p = mod) {
    v %= p;
    if (v < 0) {
        v += p;
    }
    return v;
}

ll power(ll a, ll b, ll p = mod) {
    ll c = 1;
    for (; b; b >>= 1) {
        if (b & 1) {
            c = pmod(c * a, p);
        }
        a = pmod(a * a, p);
    }
    return c;
}

ll inv(ll a) { return power(a, mod - 2); }

class DSU {
  public:
    DSU() {}
    DSU(int n) {
        // sz.assign(n + 1, 1);
        fa.assign(n + 1, 0);
        for (int i = 1; i <= n; i++) {
            fa[i] = i;
        }
    }

    int get_fa(int u) {
        if (u == fa[u]) {
            return u;
        }
        fa[u] = get_fa(fa[u]);
        return fa[u];
    }

    void unite(int u, int v) {
        u = get_fa(u);
        v = get_fa(v);
        // u -> fa[u] -> fa[v] <- v
        fa[u] = fa[v];

        /*
        if (u == v) {
            return;
        }
        if (sz[u] < sz[v]) {
            swap(u, v);
        }
        fa[v] = u;
        sz[u] += sz[v];
        */
    }

    bool is_same_set(int u, int v) { return get_fa(u) == get_fa(v); }

    vector<int> fa;
    // vector<int> sz;
};

void solve(int cas) {
    int n, m;
    cin >> n >> m;
    if (n == 0 && m == 0) {
        exit(0);
    }
    vector<tuple<int, int, int>> x;
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        x.push_back(make_tuple(u, v, w));
    }
    sort(x.begin(), x.end(), [&](const tuple<int, int, int> &i, const tuple<int, int, int> &j) -> bool { return get<2>(i) < get<2>(j); });
    int ans = 1e9;
    for (int i = 0; i < m; i++) {
        DSU dsu(n);
        int cnt = 0;
        for (int j = i; j < m; j++) {
            // auto [u, v, w] = x[j];
            int u = get<0>(x[j]);
            int v = get<1>(x[j]);
            int w = get<2>(x[j]);
            if (dsu.get_fa(u) != dsu.get_fa(v)) {
                cnt++;
                dsu.unite(u, v);
                if (cnt == n - 1) {
                    ans = min(ans, int(w - get<2>(x[i])));
                    break;
                }
            }
        }
    }
    if (ans == 1e9) {
        ans = -1;
    }
    cout << ans << endl;
}

int main() {
    ios::sync_with_stdio(false);
    // freopen("hidden.in", "r", stdin);
    // freopen("hidden.out", "w", stdout);
    int T = 1, cas = 0;
    // cin >> T;
    // while (T--) {
    while (1) {
        solve(++cas);
    }
    return 0;
}

/*
1
9
2
1689
3
946157
4
1318742807
*/
accuracy: 1
time_ms: 20
memory_kb: 3588
final_rank: 15

code_snippet: #include<bits/stdc++.h>
using namespace std;

#define rep(i, N) for(ll i = 0; i < (ll)(N); i++)

using ll = long long;
using Tpl = tuple<ll, ll, ll>;

const ll LINF = 1001001001001001001ll;

class UnionFind{
    vector<int> par, rank, sz;

    public:
    UnionFind(int N) : par(N), rank(N, 0), sz(N, 1) {
        for(int i = 0; i < N; i++) par[i] = i;
    }
    void unite(int x, int y){
        x = find(x), y = find(y);
        if(x == y) return;
        sz[x] = sz[y] = sz[x] + sz[y];
        if(rank[x] < rank[y]){
            par[x] = y;
        }
        else{
            par[y] = x;
            if(rank[x] == rank[y]) rank[x]++;
        }
    }
    int find(int x){
        if(par[x] == x) return x;
        else{
            sz[x] = sz[par[x] = find(par[x])];
            return par[x];
        }
    }
    bool same(int x, int y){
        return find(x) == find(y);
    }
    int get_size(int x){
        find(x);
        return sz[x];
    }
};

int main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);

    while(1){
        int N, M; cin >> N >> M;
        if(N == 0) return 0;

        vector<Tpl> edges(M);
        rep(i, M){
            ll u, v, w; cin >> u >> v >> w; u--, v--;
            edges[i] = make_tuple(w, u, v);
        }
        sort(edges.begin(), edges.end());

        int prev_w = -1;
        ll ans = LINF;
        rep(i, M){
            if(get<0>(edges[i]) == prev_w) continue;
            int start = get<0>(edges[i]);
            UnionFind UF(N);
            for(int j = i; j < M; j++){
                auto [w, u, v] = edges[j];
                UF.unite(u, v);
                //cout << u << " " << v << endl;
                if(UF.get_size(0) == N){
                    ans = min(ans, w - start);
                    break;
                }
            }
            if(UF.get_size(0) != N) break;
            prev_w = get<0>(edges[i]);
        }

        cout << (ans < LINF ? ans : -1) << '\n';
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3628
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define foa(s, v) for(auto &s : v)
#define all(v) v.begin(), v.end()
#define REPname(a,b,c,d,...) d
#define rep(...) REPname(__VA_ARGS__, REP2, REP1, REP0)(__VA_ARGS__)
#define REP2(i,l,r) for(int i = l; i < r; i++)
#define REP1(i, x) REP2(i,0,x)
#define REP0(x) REP1(SPJ, x)
#define sz(x) int(x.size())

template <class T>
using V=vector<T>;

template <class T>
using VV=vector<V<T>>;

template<class T>
using pqmin = priority_queue<T, V<T>, greater<T>>;
using ll = long long ;
using vi = vector<int>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using vll = vector<ll>;
using vvll = V<vll>;
constexpr ll INF = 1e18;
constexpr int inf = 1e9;
template<class T>
inline bool chmax(T &a, T b){
	return a < b ? a=b, 1 : 0;
}
template <class T>
inline bool chmin(T &a, T b) {
	return a > b ? a = b, 1 : 0;
}

template <class T>
void view(T x) {
	cerr << x;
}

template <class T>
void view(V<T> v) {
	cerr << "{ ";
	foa(t, v) {view(t) ; cerr << ", ";}
	cerr << "}";
	cerr << endl;
}


template <class T>
void view(VV<T> v) {
	cerr << "{ ";
	foa(t, v) {view(t) ; cerr << ",\n";}
	cerr << "}";
	cerr << endl;
}


// template <c0lass T>
void view(int x) {
	cerr << x;
}

#ifdef LOCAL
void debug_out() {}
template <class T>
void debug_out(T x) {
	view(x);
}
template <class H, class... T>
void debug_out(H h, T... t) {
	view(h);
	cerr << ", ";
	debug_out(t...);
}
#define debug(...)                                           \
	do {                                                     \
		cerr << __LINE__ << " [" << #__VA_ARGS__ << "] : ["; \
		debug_out(__VA_ARGS__);                              \
		cerr << "]\n";                                       \
	} while(0)
#else
#define debug(...) (void(0))
#endif
using vvi = V<vi>;

struct UF{
	vector<int> dat;
	int components;
	UF(int n) : dat(n, -1), components(n) {}
	int root(int x) 
	{
		int& p = dat[x];
		if(p < 0) return x;
		return p = root(p);
	}
	bool merge(int x, int y) {
		x = root(x);
		y = root(y);
		if(x == y) return false;
		if(-dat[x] < -dat[y]) swap(x, y);
		dat[x] += dat[y];
		dat[y]  = x;
		components--;
		return true;
	}
};

ll modpow(ll x, ll n, ll md){
	ll ret = 1 % md;
	while(n > 0){
		if(n & 1) {ret *= x; ret %= md;}
		n >>= 1;
		x *= x;
		x %= md;
	}
	if(ret < 0) ret += abs(md);
	return ret;
}

using S = ll;
using F = ll; // +
constexpr ll e = INF;
constexpr ll id = 0LL;
constexpr ll replace_e = e;
ll op(ll a, ll b) {return min(a,b);}
ll mapping(F f, S s) {return S(f+s);}
ll composition(F f, F g) {return f+g;}
struct node {
	node *l = nullptr;
	node *r = nullptr;
	int lo, hi;
	ll mset = e;
	ll madd = id;
	ll val = e;
	node(int lo, int hi) : lo(lo), hi(hi) {}
	node (vll& v, int lo, int hi) : lo(lo), hi(hi) {
		if(lo + 1 < hi) {
			int mid  = lo + (hi - lo) / 2;
			l  = new node (v, lo, mid);
			r = new node(v, mid, hi);
			val = op(l->val, r->val);
		}
		else {
			val  = v[lo];
		}
	}

	S query(int L, int R) {
		if(R <= lo || hi <= L) return e;
		if(L <=lo && hi  <= R) return val;
		push();
		return op(l->query(L, R), r->query(L,R));
	}

	void set(int L, int R, ll x) {
		if(R <= lo || hi <= L) return;
		if(L <= lo && hi <= R) mset = val = x, madd = id;
		else {
			push(), l->set (L, R, x) , r->set(L,R,x);
			val = op(l->val, r->val);
		}
	}

	void add(int L, int R, ll x) {
		if(R <= lo || hi <= L) return;
		if(L <= lo && hi <= R) {
			if(mset != replace_e) mset = mapping(x, mset);
			else madd = composition(x, madd);
			val = mapping(x, val);
		} else {
			push(), l->add(L, R, x), r->add(L, R, x);
			val = op(l->val, r->val);
		}
	}

	void push() {
		if(!l) {
			int mid = lo + (hi - lo) / 2;
			l = new node(lo, mid);
			r = new node(mid, hi);
		}
		if(mset != replace_e)
			l->set(lo, hi, mset), r->set(lo, hi, mset), mset = replace_e;
		else if(madd)
			l->add(lo, hi, madd), r->add(lo, hi, madd), madd = id;
	}
};

ll mst(int n, vector<tuple<ll, int, int>>& edges, int start_id) {
	UF uf(n);
	ll ans = -INF;
	rep(i, start_id, int(edges.size())){
		ll w;
		int a, b;
		tie(w, a, b) = edges.at(i);
		if(uf.merge(a, b)) {
			chmax(ans, w);
		}
	}
	if(uf.components > 1) return INF;
	return ans;
}

ll solve(int n){ // first : 1, second : -1, draw : 0
	int m; cin >> m;
	vector<tuple<ll, int, int>> edges;
	rep(m) {
		int a, b;
		ll w; cin >> a >> b >> w;
		edges.emplace_back(w, a-1, b-1);
	}
	sort(all(edges));
	ll ret = INF;
	rep(i, m) {
		ll res = mst(n, edges, i);
		chmin(ret, res - get<0>(edges.at(i)));
	}

	if(ret > 112345) ret = -1;
	return ret;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout << fixed << setprecision(15);
	srand((unsigned)time(NULL));
	int n;
	while(cin >> n && n) {
		cout << solve(n) << '\n';
	}
}
accuracy: 1
time_ms: 110
memory_kb: 3448
final_rank: 7

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
using P = pair<int, int>;

struct UnionFind{
    vector<int> parent;
    UnionFind(int n): parent(vector<int>(n, -1)){}

    int root(int x){
        if(parent[x] < 0) return x;
        else return parent[x] = root(parent[x]);
    }

    bool unite(int x, int y){
        if(root(x) == root(y)) return false;
        x = root(x); y = root(y);
        if(-parent[x] < -parent[y]) swap(x, y);
        parent[x] += parent[y];
        parent[y] = x;
        return true;
    }

    int count(int x){
        return -parent[root(x)];
    }
};

int main(){
    while(true){
        int n, m; cin >> n >> m;
        if(n == 0) break;

        vector<vector<P>> es(10010);
        for(int i = 0; i < m; i++){
            int a, b, w; cin >> a >> b >> w;
            es[w].emplace_back(a-1, b-1);
        }
        int ans = 1 << 30;
        for(int i = 0; i < es.size(); i++){
            if(es[i].size() == 0) continue;
            UnionFind uf(n);
            int j = i;
            for(; j < es.size(); j++){
                for(auto &it: es[j]) uf.unite(it.first, it.second);
                if(uf.count(0) == n) break;
            }
            if(uf.count(0) == n) ans = min(ans, j-i);
        }
        if(ans == 1 << 30) ans = -1;
        cout << ans << '\n';
    }
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3424
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct dsu {
  public:
    dsu() : _n(0) {}
    dsu(int n) : _n(n), parent_or_size(n, -1) {}

    int merge(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        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;
    }

    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }

    int leader(int a) {
        assert(0 <= a && a < _n);
        if (parent_or_size[a] < 0) return a;
        return parent_or_size[a] = leader(parent_or_size[a]);
    }

    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }

    std::vector<std::vector<int>> groups() {
        std::vector<int> 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<std::vector<int>> 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<int>& v) { return v.empty(); }),
            result.end());
        return result;
    }

  private:
    int _n;
    // root node: -1 * component size
    // otherwise: parent
    std::vector<int> parent_or_size;
};

int main(){
    int n, m;
    while(cin >> n >> m, n){
        vector<tuple<int,int,int>> edge(m);
        int u, v, c;
        for(int i = 0; i < m; i++){
            cin >> u >> v >> c;
            u--, v--;
            edge[i] = {c, u, v};
        }
        sort(edge.begin(), edge.end());
        auto f = [&](int st){
            dsu uf(n);
            for(int i = st; i < m; i++){
                tie(c, u, v) = edge[i];
                uf.merge(u, v);
                if(uf.size(0) == n)return c - get<0>(edge[st]);
            }
            return 1 << 30;
        };
        int ans = 1 << 30;
        for(int i = 0; i < m; i++){
            int v = f(i);
            if(v >> 30 & 1)break;
            ans = min(ans, v);
        }
        if(ans >> 30 & 1)ans = -1;
        cout << ans << '\n';
    }
}
accuracy: 1
time_ms: 20
memory_kb: 3464
final_rank: 5

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include "bits/stdc++.h"

#ifdef _MSC_VER
#include <intrin.h>  //gcc上ではこれがあると動かない。__popcnt, umul128 等用のincludeファイル。
#define __builtin_popcount __popcnt
#define __builtin_popcountll __popcnt64
// 1 の位から何個 0 が連なっているか。(0 入れると 0 を返す。)
inline unsigned int __builtin_ctz(unsigned int x) { unsigned long r; _BitScanForward(&r, x); return r; }
inline unsigned int __builtin_ctzll(unsigned long long x) { unsigned long r; _BitScanForward64(&r, x); return r; }
// 2進での leading 0 の個数。(0 入れると 32, 64 を返す。)
inline unsigned int __builtin_clz(unsigned x) { return (unsigned int)__lzcnt(x); }
inline unsigned int __builtin_clzll(unsigned long long x) { return (unsigned int)__lzcnt64(x); }
#pragma warning(disable : 4996)
#pragma intrinsic(_umul128)
#endif

//#include <atcoder/all>
//using namespace atcoder;
using namespace std;

//---------- 多倍長関連 ----------
//#include <boost/multiprecision/cpp_int.hpp>
//#include <boost/multiprecision/cpp_dec_float.hpp>
//using namespace boost::multiprecision;


typedef long long ll;
typedef long double ld;

#define int long long
#define LL128 boost::multiprecision::int128_t
#define LL boost::multiprecision::cpp_int
#define LD100 boost::multiprecision::cpp_dec_float_100
#define LD50 boost::multiprecision::cpp_dec_float_50

#define rep(i, n) for(long long i = 0; i < (n); ++i)
#define REP(i, s, n) for(long long i = (s); i < (n); ++i)
#define rrep(i, n) for(long long i = (n) - 1; i >= 0; --i)
#define sqrt(d) pow((ld) (d), 0.50)
#define PII pair<int, int>
#define MP make_pair
#define PB push_back
#define ALL(v) v.begin(), v.end()

constexpr int INF2 = std::numeric_limits<int>::max() / 2 - 10000000;
constexpr long long INF = std::numeric_limits<long long>::max() / 2 - 10000000;
const ld pi = acos(-1);

//constexpr int MOD = 1000000007; //1e9 + 7
constexpr int MOD = 998244353;  // 7 * 17 * 2^23 + 1




//---------- chmax, min 関連 ---------- 
template<class T> inline void chmax(T& a, T b) {
	if (a < b) a = b;
}
template<class T> inline void chmin(T& a, T b) {
	if (a > b) a = b;
}




//---------- gcd, lcm ---------- 
template<typename T = long long>
T my_gcd(T a, T b) {
	if (b == (T)0) return a;
	return my_gcd<T>(b, a % b);
}

template<typename T = long long>
T my_lcm(T a, T b) {
	return a / my_gcd<T>(a, b) * b;
}




// ax + by = gcd(a, b) を解く。返り値は、gcd(a, b)。
// 但し、a, b が負である場合は、返り値が正であることは保障されない。
long long my_gcd_ext(long long a, long long b, long long& x, long long& y) {
	if (b == 0) {
		x = 1; y = 0;
		return a;
	}

	long long tempo = my_gcd_ext(b, a % b, y, x);

	//bx' + ry' = gcd(a, b) → (qb + r)x + by = gcd(a, b) に戻さないといけない。// (r = a % b)
	//b(x' - qy') + (bq + r)y' = gcd(a, b) と同値変形できるから、
	// x = y', y = x' - qy'
	y -= (a / b) * x;

	return tempo;
}




//中国式剰余の定理 (CRT)
// x = base1 (mod m1) かつ x = base2 (mod m2) を解く。
// リターン値を (r, m) とすると解は x = r (mod m) で、m = lcm(m1, m2)
// 解なしの場合は (0, -1) をリターン
pair<long long, long long> CRT(long long base1, long long m1, long long base2, long long m2) {
	long long p, q;
	long long gcd0 = my_gcd_ext(m1, m2, p, q);
	if ((base2 - base1) % gcd0 != 0) return make_pair(0, -1);

	long long lcm0 = m1 * (m2 / gcd0);  // 括弧がないとオーバーフローのリスクがある。

	p *= (base2 - base1) / gcd0;
	p %= (m2 / gcd0);

	//q *= (base2 - base1) / gcd0;
	//q %= (m1 / gcd0);

	long long r = (base1 + m1 * p) % lcm0;
	if (r < 0) r += lcm0;

	return make_pair(r, lcm0);
}




//M を法として、a の逆元を返す。但し gcd(a, M) = 1。
long long my_invmod(long long a, long long M) {
	long long x = 0, y = 0;
	long long memo = my_gcd_ext(a, M, x, y);
	assert(memo == 1LL);
	x %= M;
	if (x < 0) x += M;
	return x;
}




//繰り返し2乗法 (非再帰)
//N^aの、Mで割った余りを求める。
template<typename T = long long>
constexpr T my_pow(T N, long long a, long long M) {
	assert(0 <= a);
	T x = N % M, res = (T)1;
	while (a) {
		if (a & 1) {
			res *= x;
			res %= M;
		}
		x *= x; // x は *this の (2のべき乗) 乗を管理する。
		x %= M;
		a >>= 1;
	}
	return res;
}

// 繰り返し2乗法 (非再帰)
// T = modint でも動く。
template<typename T = long long>
constexpr T my_pow(T N, long long a) {
	assert(0 <= a);
	T x = N, res = (T)1;
	while (a) {
		if (a & 1) res *= x;
		x *= x; // x は *this の (2のべき乗) 乗を管理する。
		a >>= 1;
	}
	return res;
}




// base を底としたときの、n の i桁目を、v.at(i) に入れる。
vector<signed> ll_to_vector(signed base, long long n) {
	long long tempo = n;
	long long tempo2 = n; //桁数を求めるときに使う

	signed n_digit = 1;
	while (tempo2 >= base) {
		tempo2 /= base;
		n_digit++;
	}

	vector<signed> v(n_digit, 0);   // v のサイズを適切に調整。
	long long denominator = my_pow<long long>((long long)base, (long long)(n_digit - 1));

	for (signed i = 0; i < n_digit; i++) {
		v.at(i) = tempo / denominator;
		tempo -= v.at(i) * denominator;

		denominator /= base;
	}

	return v;
}


// M 桁に足りない場合、0 を追加して強制的に M 桁にする。
vector<signed> ll_to_vector(signed base, long long n, int M) {
	vector<signed> v = ll_to_vector(base, n);
	//assert((int)v.size() <= M);

	if ((int)v.size() >= M) return v;
	else {
		int diff = M - v.size();
		vector<signed> res(diff, 0);
		for (int i = 0; i < (int)v.size(); i++) res.emplace_back(v.at(i));
		return res;
	}
}




//エラトステネスの篩で、prime で ないところに false を入れる。O(n loglog n)
// T = int (defalt, sieve が ll で間に合うことはないので。)
// vector<char> に替えるとむしろ遅くなる。
template<typename T = int>
vector<bool> sieve_bool(T N) {
	vector<bool> res(N + 1, true);
	res.at(0) = false;
	res.at(1) = false;

	for (T i = 2; 2 * i <= N; i++) {
		res.at(2 * i) = false;
	}

	for (T i = 3; i * i <= N; i += 2) {
		//ここからは奇数のみ探索。i の倍数に false を入れる。
		if (res.at(i)) {
			T j = i * i;  // i^2 未満の i の倍数には、すでに false が入っているはず。
			while (j <= N) {
				res.at(j) = false;
				j += 2 * i;
			}
		}
	}

	return res;
};




// n + 1 の サイズの vector を返す。res.at(i) には、i の 1 以外で最小の約数を入れる。
// res.at(i) == i で、i != 0, 1 なら i は素数。
// 2e8 なら、2.3 ~ 2.4 sec 程度で終わる。sieve_bool は 0.7 sec なので、3 倍強遅い。ll にすると、3.2 sec に伸びてしまう。
// T = int (defalt, sieve が ll で間に合うことはないので。)
template<typename T = int>
vector<T> sieve(T n) {
	n++; // n まで判定する。配列サイズは +1。

	vector<T> res(n, 0);
	for (T i = 1; i < n; i++) {
		if (i % 2 == 0) res.at(i) = 2;  // 偶数をあらかじめ処理。
		else res.at(i) = i; // 奇数には自分自身を入れる。
	}

	for (T i = 3; i * i < n; i += 2) {
		//ここからは奇数のみ探索。i の倍数に i を入れる。
		if (res.at(i) == i) {
			T j = i * i;  // i^2 未満の i の倍数には、すでに最小の約数が入っているはず。
			while (j < n) {
				if (res.at(j) == j) res.at(j) = i;
				j += 2 * i;
			}
		}
	}

	return res;
};




//O (sqrt(n)) で素数判定する用。
constexpr bool is_prime(long long N) {
	//有名素数
	if (N == 1000000007 || N == 1000000009) return true;
	if (N == 998244353 || N == 167772161 || N == 469762049 || N == 1224736769) return true; //g = 3;
	if (N == 924844033 || N == 1012924417) return true; //g = 5;
	if (N == 163577857) return true; //g = 23;

	//小さい素数の別処理
	if (N <= 1) return false;
	if (N == 2 || N == 3) return true;
	if (N % 2 == 0) return false;
	if (N % 3 == 0) return false;

	for (long long i = 1; (6 * i + 1) * (6 * i + 1) <= N; ++i) {
		if (N % (6 * i + 1) == 0) return false;
	}
	for (long long i = 0; (6 * i + 5) * (6 * i + 5) <= N; ++i) {
		if (N % (6 * i + 5) == 0) return false;
	}
	return true;
}

template <int n> constexpr bool is_prime_constexpr = is_prime(n);




// 素因分解アルゴリズム (O(sqrt(N)) → O(N^0.25) のρ法も持っている。
// T = long long (defalt)
template<typename T = long long>
map<T, T> PrimeFactor(T N) {
	map<T, T> res;

	T i = 2;
	while (i * i <= N) {
		while (N % i == 0) {
			res[i]++;
			N /= i;
		}

		i += 1 + (i % 2); //i == 2 の場合だけ +1, その他の場合は +2
	}

	if (N > 1) res[N]++; //sqrt((元の N)) より大きな素因数は高々1つしかない。
	return res;
}




//関数 sieve で得た、vector min_factor を持ってるときに、素因数分解を高速で行うための関数。
// T = int (defalt, sieve が ll で間に合うことはないので。)
template<typename T = int>
map<T, T> PrimeFactor2(T target, vector<T>& min_factor) {
	map<T, T> res;
	if (min_factor.empty() || (T)min_factor.size() - 1 < target) min_factor = sieve<T>(target);

	while (target > 1) {
		res[min_factor[target]]++;
		target /= min_factor[target];
	}

	return res;
}




//約数全列挙を O(sqrt(N)) で行うための関数。
vector<long long> count_dividers(long long target) {

	vector <long long> dividers, tempo;
	long long i = 1;
	while (i * i < target + 1) {
		if (target % i == 0) {
			dividers.push_back(i);
			if (i < target / i) tempo.push_back(target / i);  // if節がないと、平方数の時、sqrt(target) がダブルカウントされる。
		}
		i++;
	}

	for (long long j = 0; j < (long long)tempo.size(); j++) {
		dividers.push_back(tempo.at(tempo.size() - 1 - j));
	}

	return dividers;
}




//関数 sieve で得た、vector min_factor を持ってるときに、約数全列挙を高速で行うための関数。
// T = int (defalt, sieve が ll で間に合うことはないので。)
template<typename T = int>
vector<T> count_dividers2(T target, vector<T>& min_factor, bool is_sort = false) {

	vector<T> dividers = { 1 };
	map<T, T> memo = PrimeFactor2<T>(target, min_factor);

	for (auto&& iter = memo.begin(); iter != memo.end(); iter++) {
		vector <T> tempo = dividers;
		for (T k = 0; k < (T)tempo.size(); k++) {
			T times = 1;
			for (T j = 1; j <= (iter->second); j++) {
				times *= iter->first;
				dividers.push_back(tempo[k] * times);
			}
		}
	}

	if (is_sort) sort(dividers.begin(), dividers.end());  //sortしないと小さい順に並ばないが、必要ないなら消しても良い。
	return dividers;
}




class UnionFind {
public:
	vector<int> parent;
	vector<int> rank;
	vector<int> v_size;

	UnionFind(int N) : parent(N), rank(N, 0), v_size(N, 1) {
		rep(i, N) {
			parent[i] = i;
		}
	}

	int root(int x) {
		if (parent[x] == x) return x;
		return parent[x] = root(parent[x]); //経路圧縮
	}

	void unite(int x, int y) {
		int rx = root(x);
		int ry = root(y);

		if (rx == ry) return; //xの根とyの根が同じなので、何もしない。
		if (rank[rx] < rank[ry]) {
			parent[rx] = ry;
			v_size[ry] += v_size[rx];
		}
		else {
			parent[ry] = rx;
			v_size[rx] += v_size[ry];
			if (rank[rx] == rank[ry]) rank[rx]++;
		}
	}

	bool same(int x, int y) {
		return (root(x) == root(y));
	}

	int count_tree() {
		int N = parent.size();
		int res = 0;

		rep(i, N) {
			if (root(i) == i) res++;
		}

		return res;
	}

	int size(int x) {
		return v_size[root(x)];
	}
};




// 幾何。二点間距離。
ld calc_dist(int x1, int y1, int x2, int y2) {
	int tempo = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
	ld res = sqrt((ld)tempo);
	return res;
}




//ランレングス圧縮
vector<pair<int, char>> RunLength(const string& S) {
	int N = S.size();
	vector<pair<int, char>> memo;

	if (N == 1) {
		memo.push_back(MP(1, S.at(0)));
		return memo;
	}

	int tempo = 1;
	for (int i = 1; i < N; i++) {
		if (i != N - 1) {
			if (S.at(i) == S.at(i - 1)) tempo++;
			else {
				memo.push_back(MP(tempo, S.at(i - 1)));
				tempo = 1;
			}
		}
		else {
			if (S.at(i) == S.at(i - 1)) {
				tempo++;
				memo.push_back(MP(tempo, S.at(i - 1)));
			}
			else {
				memo.push_back(MP(tempo, S.at(i - 1)));
				memo.push_back(MP(1, S.at(i)));
			}
		}
	}

	return memo;
}




void printf_ld(ld res) {
	printf("%.12Lf\n", res);
	//cout << std::fixed << std::setprecision(12) << res << endl;
}

template<typename T = long long>
void print_vec(vector<T> v) {
	int N = v.size();
	rep(i, N) {
		if (i != N - 1) cout << v.at(i) << " ";
		else cout << v.at(i) << endl;
	}
}

template<typename T = long long>
void print_vec(deque<T> v) {
	int N = v.size();
	rep(i, N) {
		if (i != N - 1) cout << v.at(i) << " ";
		else cout << v.at(i) << endl;
	}
}




//mint 構造体。自動で mod を取る。
//m はコンパイル時に決まる定数である必要があるので、入力を用いることはできない。
//割り算に m の素数判定が必要になり、is_prime に依存するようになった。
//※ constexpr 関数の const 修飾は C++11 では許されない。
template<int m, typename T = long long> class mint {
private:
	T _val;
public:
	//---------- コンストラクタ ----------
	constexpr mint(T v = 0LL) noexcept : _val(v% m) {
		if (_val < 0) _val += m;
	}

	constexpr T val() const noexcept {
		return _val;
	}

	//------------------------------ 二項演算子のオーバーロード ------------------------------
	constexpr mint& operator += (const mint& r) noexcept {
		_val += r._val;
		if (_val >= m) _val -= m;
		return *this;
	}
	constexpr mint& operator -= (const mint& r) noexcept {
		_val -= r._val;
		if (_val < 0) _val += m;
		return *this;
	}
	constexpr mint& operator *= (const mint& r) noexcept {
		_val *= r._val; _val %= m;
		return *this;
	}
	constexpr mint& operator /= (const mint& r) noexcept {
		if (!prime) {
			//a * u + b * v = 1 を互除法で解く。但し、gcd(a, m) == 1 でなければならない。
			T a = r._val, b = m, u = 1, v = 0;
			while (b) {
				T q = a / b;
				a -= q * b; swap(a, b); //互除法。余りをとって swap。
				u -= q * v; swap(u, v);
			}
			//assert(a == 1); //gcd(r._val, m) == 1;
			_val *= u; _val %= m;
			if (_val < 0) _val += m;
		}
		else {
			//フェルマーの小定理。底が prime である場合のみ使用可能。
			*this *= r.modpow(m - 2);
		}
		return *this;
	}

	constexpr mint operator + (const mint& r) const noexcept { return mint(*this) += r; }
	constexpr mint operator - (const mint& r) const noexcept { return mint(*this) -= r; }
	constexpr mint operator * (const mint& r) const noexcept { return mint(*this) *= r; }
	constexpr mint operator / (const mint& r) const noexcept { return mint(*this) /= r; }

	constexpr bool operator == (const mint& r) const noexcept {
		return this->_val == r._val;
	}
	constexpr bool operator != (const mint& r) const noexcept {
		return this->_val != r._val;
	}

	//------------------------------ 単項演算子のオーバーロード ------------------------------
	//---------- 前置インクリメントのオーバーロード ----------
	constexpr mint operator ++() noexcept { this->_val++; if (this->_val == m) this->_val = 0; return mint(*this); }
	constexpr mint operator --() noexcept { if (this->_val == 0) this->_val = m;  this->_val--; return mint(*this); }
	//---------- 後置インクリメントのオーバーロード ----------
	constexpr mint operator++(signed) noexcept { mint temp(_val); ++_val; if (_val == m) _val = 0; return temp; }
	constexpr mint operator--(signed) noexcept { mint temp(_val); if (_val == 0) _val = m;  --_val; return temp; }

	constexpr mint operator -() const noexcept { return mint(-_val); }

	//---------- 入出力のオーバーロード ----------
	friend constexpr ostream& operator << (ostream& os, const mint<m, T>& x) noexcept {
		return os << x._val;
	}
	friend istream& operator >> (istream& is, mint<m, T>& x) noexcept {
		T init_val;
		is >> init_val;
		x = mint<m, T>(init_val);
		return is;
	}

	//---------- 逆元 ----------
	constexpr mint<m, T> inverse() const noexcept {
		mint<m, T> e(1);
		return e / (*this);
	}

private:
	// 愚直な O(sqrt(m)) の素数判定; 余りに m が大きすぎると、コンパイル時の定数式の評価に失敗するが、1e11 程度までなら大丈夫。
	// Miller-Rabin を使ってもよい。
	static constexpr bool prime = is_prime_constexpr<m>;


	//---------- 繰り返し二乗法 ----------
	constexpr mint<m, T> modpow(long long n) const noexcept {
		assert(0 <= n);
		mint<m, T> x = *this, r = 1;
		while (n) {
			if (n & 1) r *= x;
			x *= x; // x は *this の (2のべき乗) 乗を管理する。
			n >>= 1;
		}
		return r;
	}
};

using modint = mint<MOD, long long>;




vector<modint> dp_fac;
vector<modint> dp_fac_inv;

// x!まで計算するときに最初に呼び出す。o(x).
template<typename T = modint>
void fac_initialize(int x, vector<T>& dp = dp_fac, vector<T>& dp_inv = dp_fac_inv) {
	if ((int)dp.size() <= x) {
		int n = dp.size(); if (n == 0) ++n;
		dp.resize(x + 1, (T)1);
		for (int i = n; i <= x; ++i) {
			dp.at(i) = dp.at(i - 1) * i;
		}
	}

	if ((int)dp_inv.size() <= x) {
		int n = dp_inv.size();
		dp_inv.resize(x + 1, (T)1);
		dp_inv.at(x) /= dp.at(x);
		for (int i = x - 1; i >= n; --i) {
			dp_inv.at(i) = dp_inv.at(i + 1) * (i + 1);
		}
	}
}

// 階乗。x ! まで計算する。結果は dp (デフォルトで dp_fac<modint>) に保存する。
// long long にするためには、第二引数に vector<long long> を指定する必要がある。20 ! = 2.43e18 まで long long に入る。
template<typename T = modint>
T factorial(int x, vector<T>& dp = dp_fac) {
	assert(x >= 0);

	//既に計算済み
	if ((int)dp.size() > x) {
		return dp.at(x);
	}

	int n = dp.size();
	//dp サイズを x + 1 に伸ばす。
	for (int i = n; i < x + 1; i++) {
		if (i == 0) dp.push_back((T)1);
		else dp.push_back(dp.back() * i);
	}

	return dp.at(x);
}

template<typename T = modint>
T factorial_inv(int x, vector<T>& dp = dp_fac_inv) {
	assert(x >= 0);

	//既に計算済み
	if ((int)dp.size() > x) {
		return dp.at(x);
	}

	int n = dp.size();
	//dp サイズを x + 1 に伸ばす。
	for (int i = n; i < x + 1; i++) {
		if (i == 0) dp.push_back((T)1);
		else dp.push_back(dp.back() / i);
	}

	return dp.at(x);
}


// 二項係数 N_C_a 
template<typename T = modint, typename U = int>
T my_comb(U N, U a, vector<T>& dp = dp_fac, vector<T>& dp_inv = dp_fac_inv) {
	if (N < a) return (T)0;

	T ans = factorial<T>(N, dp);
	ans *= factorial_inv<T>(a, dp_inv);
	ans *= factorial_inv<T>(N - a, dp_inv);

	return ans;
}

//二項係数 N_C_a (1点計算用)
template<typename T, typename U = int>
T my_comb2(U N, U a) {
	if (N < a) return (T)0;

	T answer = 1;
	for (U i = (U)0; i < a; i++) {
		answer *= (N - i);
		answer /= i + 1;
	}

	return answer;
}




ld now_clock() {
	ld t = (ld)clock() / (ld)CLOCKS_PER_SEC;
	return t;
}






//四近傍
const vector<int> vdh = { 1, -1, 0, 0 };
const vector<int> vdw = { 0, 0, 1, -1 };


// グラフ構造体 (辺の重みあり)
// add_edge, add_biedge (有向辺、無向辺の追加)
// bfs01, dijkstra (最短路) の機能
// route (最短経路を求める) 機能
// cnt_route (最短路が何通りあるか求める) 機能 → ABC 021 C - 正直者の高橋くん
// from_grid(const vector<string>& S); grid からの変換
// Kruskal (UnionFind に依存), Prim 法での最小全域木 (MST) のコスト
// bfsTopSort (トポロジカルソート)
// IsClosed() 閉路の有無を判定し、閉路がある場合はその 1つを返す。(無向グラフの場合のみ)
template<typename T = long long>
struct edge {
	int to;
	T weight;
	int index; //何番目の辺か。

	constexpr bool operator < (const edge& r) const noexcept {
		if (weight != r.weight) return (weight < r.weight);
		else return (index < r.index);
	}
	constexpr bool operator > (const edge& r) const noexcept {
		if (weight != r.weight) return (weight > r.weight);
		else return (index > r.index);
	}
};
template<typename T> bool operator== (const edge<T>& a, const edge<T>& b) { return (a.to == b.to && a.weight == b.weight && a.index == b.index); };


template<typename T = long long>
struct edge2 {
	int from;
	int to;
	T weight;

	constexpr bool operator < (const edge2& r) const noexcept {
		if (weight != r.weight) return (weight < r.weight);
		else return (from < r.from);
	}
};


template<typename T = long long>
class graph {
	int sp = -1; // 始点
public:
	vector<vector<edge<T>>> G;
	vector<edge2<T>> edges;
	vector<T> dist; // 始点からの距離
	vector<int> prev; // 始点から最短距離で進む際の直前の頂点
	vector<int> prev_edge; // 始点から最短距離で進む際の直前の辺
	bool closed = false; //閉路があるか否か。(無向グラフの場合のみ)

	graph(int _n) : N(_n), uf(_n) { initialize(_n); };
	graph() : N(0), uf(0) {};


	// G に対して、有向辺を加える。
	void add_edge(int from, int to, T weight = (T)1) {
		assert(0 <= from && from < N);
		assert(0 <= to && to < N);
		assert((T)0 <= weight);

		G.at(from).emplace_back(edge<T>{ to, weight, (int)edges.size() });
		edges.push_back(edge2<T>{from, to, weight});

		//無向辺を2回見ないための条件。
		if (from < to) {
			if (uf.root(from) == uf.root(to)) closed = true;
			else uf.unite(from, to);
		}
	}


	// G に対して、無向辺を加える。
	void add_biedge(int from, int to, T weight = (T)1) {
		add_edge(from, to, weight);
		add_edge(to, from, weight);
	}


	// 最短路 (01-BFS / weight が 0 or 1 のみの場合使える / 複数始点)
	void bfs01(vector<int> vs) {
		const T ini_dist = -1;
		assert(!vs.empty());

		deque<int> que;
		dist.assign(N, ini_dist);
		prev.assign(N, -1);
		prev_edge.assign(N, -1);

		for (auto&& s : vs) {
			assert(0 <= s && s < N);
			que.push_front(s); dist.at(s) = 0;
		}

		while (!que.empty()) {
			int v = que.front(); que.pop_front();
			for (edge<T> e : G.at(v)) {
				int nextv = e.to;

				//if の 第二項が無いと、本当はcost = 0 で行けるのに、先に cost = 1 の辺を発見した場合バグる。
				if (dist.at(nextv) != ini_dist && dist.at(nextv) <= dist.at(v) + e.weight) continue;
				dist.at(nextv) = dist.at(v) + e.weight;
				if ((int)vs.size() == 1) {
					prev.at(nextv) = v;
					prev_edge.at(nextv) = e.index;
				}

				if (e.weight) que.push_back(nextv);
				else que.push_front(nextv);
			}
		}
	}


	// 最短路 (01-BFS / weight が 0 or 1 のみの場合使える / 単一始点)
	void bfs01(int s) {
		vector<int> vs = { s };
		sp = s;
		bfs01(vs);
	}


	//最短路 dijkstra (経路復元あり)
	void dijkstra(int s) {
		assert(0 <= s && s < N);
		sp = s;

		dist.assign(N, INF);
		prev.assign(N, -1);
		prev_edge.assign(N, -1);

		//first が最短距離、second が頂点番号。
		priority_queue<pair<T, int>, vector<pair<T, int>>, greater<pair<T, int>>> que;
		dist.at(s) = (T)0; que.push(make_pair((T)0, s));

		while (!que.empty()) {
			pair<T, int> p = que.top(); que.pop();
			int v = p.second;
			if (dist.at(v) < p.first) continue;  //最短距離がすでに更新されているので無視。

			for (int i = 0; i < (int)G.at(v).size(); i++) {
				edge<T> e = G.at(v).at(i);
				if (dist.at(e.to) > dist.at(v) + e.weight) {
					dist.at(e.to) = dist.at(v) + e.weight;
					prev.at(e.to) = v;
					prev_edge.at(e.to) = e.index;
					que.push(make_pair(dist.at(e.to), e.to));
				}
			}
		}
	}


	// 始点 sp からの距離 dist が求まっている際に、sp から 頂点 v への経路を返す。
	// sp から v にたどりつけない場合バグる。
	vector<int> route(int v) {
		assert(sp != -1);
		vector<int> res = { v }; // 頂点番号

		while (res.back() != sp) {
			int now = res.back();
			int next_v = prev.at(now);
			res.push_back(next_v);
		}

		reverse(res.begin(), res.end());
		return res;
	}


	// 始点 sp からの距離 dist が求まっている際に、
	// 始点 sp から頂点 i までの最短距離での行き方を求める。
	template<typename U = modint>
	U cnt_route(int i, vector<U>& cnt, vector<bool>& seen) {
		assert(sp != -1);
		assert((int)cnt.size() == N);
		assert((int)seen.size() == N);

		if (seen.at(i)) return cnt.at(i);
		else if (i == sp) {
			seen.at(i) = true;
			return cnt.at(i) = (U)1;
		}
		else {
			U sum = 0;
			for (auto& e : G.at(i)) {
				int nextv = e.to;
				if (dist.at(i) == dist.at(nextv) + e.weight) {
					sum += cnt_route(nextv, cnt, seen);
				}
			}

			seen.at(i) = true;
			return cnt.at(i) = sum;
		}
	}





	// grid から隣接グラフを構築。
	void from_grid(const vector<string>& S) {
		assert(!S.empty());

		int H = S.size();
		int W = S.at(0).size();

		int N = H * W;
		initialize(N);
		for (int h = 0; h < H; ++h) {
			for (int w = 0; w < W; ++w) {
				for (int i = 0; i < (int)vdh.size(); ++i) {
					int dh = vdh.at(i), dw = vdw.at(i);
					if (h + dh < 0 || H <= h + dh) continue;
					if (w + dw < 0 || W <= w + dw) continue;

					int v = h * W + w;
					int nextv = (h + dh) * W + (w + dw);
					if (S.at(h + dh).at(w + dw) == '#') { //壁
						continue;
					}
					else {
						add_edge(v, nextv, 1);
					}

				}
			}
		}
	}





	// (無向グラフの場合のみ)
	//---------- Prim 法によって、最小全域木 (MST, Minimum Spanning Tree) 問題を解く ----------
	// sp を含む連結成分の最小全域木のコストと、その頂点数 (元グラフが連結なら N になる) の pair を返す。
	pair<T, int> Prim(int sp = 0) {
		assert(0 <= sp && sp < N);

		T sum = 0;
		int marked_cnt = 0;
		vector<bool> marked(N, false);

		priority_queue<edge<T>, vector<edge<T>>, greater<edge<T>>> que;

		// ----- ↓初期頂点の処理↓ -----
		++marked_cnt;
		marked[sp] = true;
		for (auto&& e : G[sp]) que.push(e);
		// ----- ↑初期頂点の処理↑ -----

		while (marked_cnt < N && !que.empty()) {
			auto e = que.top(); que.pop();
			int nextv = e.to;

			if (marked[nextv]) continue;
			++marked_cnt;
			marked[nextv] = true;
			for (auto&& nexte : G[nextv]) que.push(nexte);

			sum += e.weight;
		}

		return make_pair(sum, marked_cnt);
	}


	// (無向グラフの場合のみ)
	//---------- Kruskal 法によって、最小全域木 (MST, Minimum Spanning Tree) 問題を解く ----------
	//---------- UnionFindも必要 ---------- 
	// 最小全域木のコストを返す。連結でなければ INF を返す。
	T Kruskal() {
		assert(edges.size() % 2 == 0);
		int E = edges.size() / 2;

		vector<edge2<T>> es;
		for (int i = 0; i < (int)edges.size(); i += 2) {
			int v1 = edges.at(i).from;
			int v2 = edges.at(i).to;
			T w = edges.at(i).weight;

			assert(edges.at(i + 1).from == v2);
			assert(edges.at(i + 1).to == v1);
			assert(edges.at(i + 1).weight == w);

			es.push_back(edge2<T>{v1, v2, w});
		}
		std::sort(es.begin(), es.end());


		int sum = 0;
		UnionFind tree(N);

		rep(i, E) {
			edge2<T> e = es.at(i);
			if (!tree.same(e.from, e.to)) {
				tree.unite(e.from, e.to);
				sum += e.weight;
			}
		}

		// そもそも連結グラフだったか判定。
		rep(v, N) {
			if (!tree.same(0, v)) return INF;
		}

		return sum;
	}





	// 返り値.first; トポロジカルソート可能か否か。
	// 返り値.second; トポロジカルソート可能な場合の一例。
	pair<bool, vector<int>> bfsTopSort() {
		vector<int> CntIn(N, 0);
		for (int i = 0; i < N; ++i) {
			for (int j = 0; j < (int)G.at(i).size(); ++j) {
				int v = G.at(i).at(j).to;
				++CntIn.at(v);
			}
		}

		vector<int> res;
		queue<int> que;
		//priority_queue<int, vector<int>, greater<int>> que; //辞書順になる。

		for (int i = 0; i < N; ++i) {
			if (CntIn.at(i) == 0) {
				que.push(i);
				--CntIn.at(i);
			}
		}

		while (!que.empty()) {
			int v = que.front(); que.pop();
			//int v = que.top(); que.pop(); //priority_que の場合
			res.push_back(v);

			for (int i = 0; i < (int)G.at(v).size(); ++i) {
				int next_v = G.at(v).at(i).to;

				if (CntIn.at(next_v) == -1) {
					//トポロジカルソート失敗。
					return make_pair(false, vector<int>());
				}

				--CntIn.at(next_v);
				if (CntIn.at(next_v) == 0) {
					que.push(next_v);
				}
			}
		}


		if (res.size() == N) {
			return make_pair(true, res);
		}
		else {
			return make_pair(false, vector<int>());
		}
	}





	//閉路検出を行う。(無向グラフの場合)
	//first; 閉路があるか否かの bool
	//second; 閉路がある場合の一つの例。
	pair<bool, vector<int>> IsClosed() {
		vector<bool> seen(N, false);

		for (int v = 0; v < N; ++v) {
			if (seen.at(v)) continue;
			vector<int> vec;
			bool flag = dfs_closed(v, -1, vec, seen);

			if (flag) {
				vector<int> res;
				while (!vec.empty()) {
					res.push_back(vec.back());
					vec.pop_back();

					if (res.size() > 1 && res.front() == res.back()) break;
				}

				assert((int)res.size() > 1);
				return make_pair(true, res);
			}
		}


		vector<int> vec;
		return make_pair(false, vec);
	}





private:
	int N;
	UnionFind uf; //辺つなぐ際の閉路検出に使う。


	// 初期化
	void initialize(int n) {
		G.assign(n, vector<edge<T>>());
		sp = -1;
		dist.assign(n, INF);
		prev.assign(n, -1);
		prev_edge.assign(n, -1);
	}



	//閉路検出に使う dfs (無向グラフの場合)
	bool dfs_closed(int v, int from, vector<int>& vec, vector<bool>& seen) {
		vec.push_back(v);
		if (seen.at(v)) return true;
		else seen.at(v) = true;

		for (auto&& ed : G.at(v)) {
			int next_v = ed.to;
			if (next_v == from) continue;

			bool flag = dfs_closed(next_v, v, vec, seen);
			if (flag) return true;
		}

		vec.pop_back();
		return false;
	}
};





signed main() {

	vector<int> vres;
	while (true) {
		int N, M;
		cin >> N >> M;
		if (N == 0 && M == 0) break;

		vector<int> a(M), b(M), w(M);
		rep(i, M) {
			cin >> a.at(i) >> b.at(i) >> w.at(i);
			--a.at(i); --b.at(i);
		}


		graph<int> G(N);
		rep(i, M) G.add_biedge(a.at(i), b.at(i), w.at(i));


		vector<edge2<int>> es;
		for (int i = 0; i < (int)G.edges.size(); i += 2) {
			int v1 = G.edges.at(i).from;
			int v2 = G.edges.at(i).to;
			int w = G.edges.at(i).weight;


			es.push_back(edge2<int>{v1, v2, w});
		}
		std::sort(es.begin(), es.end());


		int res = INF;
		rrep(i, (int)es.size()) {
			UnionFind tree(N);
			int tmp = 0;
			tree.unite(es.at(i).from, es.at(i).to);

			rrep(j, i) {
				edge2<int> e = es.at(j);
				if (!tree.same(e.from, e.to)) {
					tree.unite(e.from, e.to);
					tmp = es.at(i).weight - es.at(j).weight;
				}
			}

			rep(v, N) {
				if (!tree.same(0, v)) {
					tmp = INF;
					break;
				}
			}

			chmin(res, tmp);
		}

		if (res != INF) vres.push_back(res);
		else vres.push_back(-1);
	}

	rep(i, (int)vres.size()) cout << vres.at(i) << endl;
}
accuracy: 1
time_ms: 90
memory_kb: 3972
final_rank: 19

code_snippet: #include <bits/stdc++.h>
//#include <atcoder/all>
//using namespace atcoder;
using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vb = vector<bool>;
using vvb = vector<vb>;
using vvvb = vector<vvb>;
using vd = vector<double>;
using vvd = vector<vd>;
using vvvd = vector<vvd>;
#define all(A) A.begin(),A.end()
#define rep(i, n) for (ll i = 0; i < (ll) (n); i++)
using pqr = priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>>;

template<class T>
bool chmax(T& p, T q) {
    if (p < q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}
template<class T>
bool chmin(T& p, T q) {
    if (p > q) {
        p = q;
        return 1;
    }
    else {
        return 0;
    }
}

ll gcd(ll(a), ll(b)) {
    ll c = a;
    while (a % b != 0) {
        c = a % b;
        a = b;
        b = c;
    }
    return b;
}
ll modPow(long long a, long long n, long long p) {
    if (n == 0) return 1; // 0乗にも対応する場合
    if (n == 1) return a % p;
    if (n % 2 == 1) return (a * modPow(a, n - 1, p)) % p;
    long long t = modPow(a, n / 2, p);
    return (t * t) % p;
}
struct dsu {
public:
    dsu() : _n(0) {}
    dsu(int n) : _n(n), par_size(n, -1) {}

    int merge(int a, int b) {
        int x = leader(a), y = leader(b);
        if (x == y) return x;
        if (-par_size[x] < -par_size[y]) swap(x, y);
        par_size[x] += par_size[y];
        par_size[y] = x;
        return x;
    }

    bool same(int a, int b) {
        return leader(a) == leader(b);
    }

    int leader(int a) {
        if (par_size[a] < 0) return a;
        return par_size[a] = leader(par_size[a]);
    }

    int size(int a) {
        return -par_size[leader(a)];
    }

    vector<vector<int>> groups() {
        std::vector<int> leader_buf(_n), gr_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            gr_size[leader_buf[i]]++;
        }
        std::vector<vector<int>> res(_n);
        for (int i = 0; i < _n; i++) {
            res[i].reserve(gr_size[i]);
        }
        for (int i = 0; i < _n; i++) {
            res[leader_buf[i]].push_back(i);
        }
        res.erase(
            remove_if(res.begin(), res.end(),
                [&](const vector<int>& v) { return v.empty(); }),
            res.end());
        return res;
    }
private:
    int _n;
    vector<int> par_size;
};

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    while (1) {
        ll N, M;
        cin >> N >> M;
        if (N == 0)return 0;
        vector<pair<ll, pair<ll, ll>>> E(M);
        rep(i, M) {
            ll U, V, W;
            cin >> U >> V >> W;
            U--; V--;
            E[i] = { W,{U,V} };
        }
        sort(all(E));
        ll an = 1e18;
        rep(i, M) {
            ll res = 0;

            res += E[i].first;
            ll L = i-1, R = M;
            while (R - L > 1) {
                dsu d(N);
                ll mid = (R + L) / 2;
                for (ll j = i; j <= mid; j++) {
                    d.merge(E[j].second.first, E[j].second.second);
                }
                if (d.size(0) == N) {
                    chmin(an, E[mid].first - E[i].first);
                    R = mid;
                }
                else {
                    L = mid;
                }
            }


        }
        cout << (an < 1e16 ? an : -1) << endl;
    }
}
accuracy: 1
time_ms: 140
memory_kb: 3548
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (int i = (int)(s); i < (int)(t); ++i)
#define revrep(i, t, s) for (int i = (int)(t)-1; i >= (int)(s); --i)
#define all(x) begin(x), end(x)
template <typename T> bool chmax(T& a, const T& b) { return a < b ? (a = b, 1) : 0; }
template <typename T> bool chmin(T& a, const T& b) { return a > b ? (a = b, 1) : 0; }

class UnionFind {
public:
    UnionFind() = default;
    explicit UnionFind(int n) : data(n, -1) {}

    int find(int x) {
        if (data[x] < 0) return x;
        return data[x] = find(data[x]);
    }

    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        if (data[x] > data[y]) std::swap(x, y);
        data[x] += data[y];
        data[y] = x;
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int size(int x) {
        return -data[find(x)];
    }

private:
    std::vector<int> data;
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);

    while (true) {
        int n, m;
        cin >> n >> m;
        if (n == 0) break;
        vector<tuple<int, int, int>> edges;
        rep(i,0,m) {
            int a, b, w;
            cin >> a >> b >> w;
            --a, --b;
            edges.push_back({w, a, b});
        }
        sort(all(edges));
        int ans = 1e9;
        rep(i,0,m) {
            UnionFind uf(n);
            int mi = get<0>(edges[i]);
            int ma = 0;
            rep(j,i,m) {
                auto [w, a, b] = edges[j];
                if (!uf.same(a, b)) {
                    uf.unite(a, b);
                    chmax(ma, w);
                }
            }
            if (uf.size(0) == n) chmin(ans, ma-mi);
        }
        cout << (ans < 1e9 ? ans : -1) << endl;
    }
}
accuracy: 1
time_ms: 70
memory_kb: 3576
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair<ll, ll> pint;
#define rep(i, n) for(ll i = 0; i < (ll)n; i++)
#define ALL(v) (v).begin(), (v).end()
const ll INF = 1e16;
/* Union-Find木 */

struct UnionFind {
  private:
    vector<int> parent;
  
  public:
    UnionFind(int n) : parent(n, -1) { }
    void init(int n) { parent.assign(n, -1); }
 
    int root(int x) {
      if (parent[x] < 0) return x;
      else return parent[x] = root(parent[x]);
    }
 
    bool issame(int x, int y) {
      return root(x) == root(y);
    }
 
    void merge(int x, int y) { //親、子
      x = root(x);
      y = root(y);
      if (x == y) return;
      if (parent[x] > parent[y]) swap(x, y);
      parent[x] += parent[y]; // sizeを調整
      parent[y] = x; // 大きい木の根に小さい木をつける, yの親はx
    }
 
    int size(int x) {
      return -parent[root(x)];
    }
  
};

int main() {
  while(1) {
    ll N, M; cin >> N >> M;
    ll ans = +INF;
    if(N == 0 && M == 0) break;
    vector<pair<ll, pint>> P;
    rep(i, M) {
      ll a, b, c; cin >> a >> b >> c;
      a--; b--;
      P.push_back(pair<ll, pint>(c, pint(a, b)));
    }
    sort(ALL(P));
    rep(i, M) {
      UnionFind uf(N);
      ll MIN = +INF;
      ll MAX = -INF;
      for(ll j = i; j < M; j++) {
        if(uf.issame(P[j].second.first, P[j].second.second)) continue;
        uf.merge(P[j].second.first, P[j].second.second);
        MIN = min(MIN, P[j].first);
        MAX = max(MAX, P[j].first);
      }
      bool flag = true;
      rep(j, N) if(!uf.issame(0, j)) flag = false;
      if(flag) ans = min(ans, MAX-MIN);
    }
    if(ans == INF) cout << -1 << endl;
    else cout << ans << endl;
  }
}
accuracy: 1
time_ms: 110
memory_kb: 3488
final_rank: 9

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i = 0; i < (n); i++)
using namespace std;
typedef long long ll;

class union_find {
  private:
    vector<int> parent;

  public:
    union_find(int n) : parent(n, -1) {}
    bool unite(int x, int y) {
        x = root(x), y = root(y);
        if(x != y) {
            if(size(x) < size(y)) swap(x, y);
            parent[x] += parent[y];
            parent[y] = x;
            return true;
        }
        return false;
    }
    int root(int x) { return parent[x] < 0 ? x : parent[x] = root(parent[x]); }
    int size(int x) { return -parent[root(x)]; }
    bool same(int x, int y) { return root(x) == root(y); }
};

int main(){
    cin.tie(0);
    ios::sync_with_stdio(0);
    
    while(true) {
        int n,m; cin >> n >> m; if(n == 0 && m == 0) break;
        vector<tuple<int,int,int>> edges;
        rep(_,m) {
            int a,b,w; cin >> a >> b >> w; a--; b--;
            edges.push_back({a, b, w});
        }

        sort(edges.begin(), edges.end(), [&](auto e1, auto e2) {
            auto [a1, b1, w1] = e1;
            auto [a2, b2, w2] = e2;
            return w1 < w2;
        });

        int ans = 1e9;
        rep(i,m) {
            union_find uf(n);
            for(int k = i; k < m; k++) {
                auto [u, v, w] = edges[k];
                if(uf.unite(u, v) && uf.size(u) == n) {
                    auto [ui, vi, wi] = edges[i];
                    ans = min(ans, w - wi);
                    break;
                }
            }
        }

        cout << (ans == 1e9 ? -1 : ans) << endl;
    }
}
accuracy: 1
time_ms: 20
memory_kb: 3584
final_rank: 13

code_snippet: /*
https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1280

実装には15分ほどかかった。各辺をコストでソートしたのち、辺iを起点に最小全域木を構成して
その木のslimnessを計算することを全ての辺で行い、最小のslimnessを求める。
*/
#include <cmath>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct UnionTree
{
    vector<int> parents, size;
    UnionTree() {}
    UnionTree(int n)
    {
        parents.resize(n, 0);
        size.resize(n, 0);
        for (int i = 0; i < n; i++)
        {
            makeTree(i);
        }
    }

    void makeTree(int x)
    {
        parents[x] = x;
        size[x] = 1;
    }

    int findRoot(int x)
    {
        if (parents[x] != x)
        {
            parents[x] = findRoot(parents[x]);
        }
        return parents[x];
    }

    bool isSame(int x, int y)
    {
        return findRoot(x) == findRoot(y);
    }

    bool unite(int x, int y)
    {
        x = findRoot(x);
        y = findRoot(y);
        if (x == y)
        {
            return false;
        }
        else
        {
            if (size[x] > size[y])
            {
                parents[y] = x;
                size[x] += size[y];
            }
            else
            {
                parents[x] = y;
                size[y] += size[x];
            }
            return true;
        }
    }
};

struct Edge
{
    int u;
    int v;
    int cost;
};
bool comp_e(const Edge &e1, const Edge &e2) { return e1.cost < e2.cost; }

int kruskal(vector<Edge> edges, int N, int M, int start)
{
    UnionTree uft = UnionTree(N);
    int max_cost = 0;
    int min_cost = 100000;
    Edge e;

    for (int i = start; i < M; i++)
    {
        e = edges[i];
        if (!uft.isSame(e.u, e.v))
        {
            uft.unite(e.u, e.v);
            max_cost = max(max_cost, e.cost);
            min_cost = min(min_cost, e.cost);
        }
    }
    for (int i = 0; i < start; i++)
    {
        e = edges[i];
        if (!uft.isSame(e.u, e.v))
        {
            uft.unite(e.u, e.v);
            max_cost = max(max_cost, e.cost);
            min_cost = min(min_cost, e.cost);
        }
    }
    if (uft.size[uft.findRoot(0)] != N)
        return -1;
    else
        return max_cost - min_cost;
}

int main()
{
    int N, M;
    int a, b, w;

    while (cin >> N >> M)
    {
        if (N == 0 && M == 0)
            break;
        else if (M == 0)
            cout << -1 << endl;
        else
        {

            vector<Edge> edges;
            for (int i = 0; i < M; i++)
            {
                cin >> a >> b >> w;
                Edge e = {a - 1, b - 1, w};
                edges.push_back(e);
            }
            sort(edges.begin(), edges.end(), comp_e);

            int min_slimness = 100000;
            for (int i = 0; i < M; i++)
            {
                min_slimness = min(min_slimness, kruskal(edges, N, M, i));
                if (min_slimness == -1)
                    break;
            }

            cout << min_slimness << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 3532
final_rank: 11

code_snippet: #include <cmath>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct UnionTree
{
    vector<int> parents, size;
    UnionTree() {}
    UnionTree(int n)
    {
        parents.resize(n, 0);
        size.resize(n, 0);
        for (int i = 0; i < n; i++)
        {
            makeTree(i);
        }
    }

    void makeTree(int x)
    {
        parents[x] = x;
        size[x] = 1;
    }

    int findRoot(int x)
    {
        if (parents[x] != x)
        {
            parents[x] = findRoot(parents[x]);
        }
        return parents[x];
    }

    bool isSame(int x, int y)
    {
        return findRoot(x) == findRoot(y);
    }

    bool unite(int x, int y)
    {
        x = findRoot(x);
        y = findRoot(y);
        if (x == y)
        {
            return false;
        }
        else
        {
            if (size[x] > size[y])
            {
                parents[y] = x;
                size[x] += size[y];
            }
            else
            {
                parents[x] = y;
                size[y] += size[x];
            }
            return true;
        }
    }
};

struct Edge
{
    int u;
    int v;
    int cost;
};
bool comp_e(const Edge &e1, const Edge &e2) { return e1.cost < e2.cost; }

int kruskal(vector<Edge> edges, int N, int M, int start)
{
    UnionTree uft = UnionTree(N);
    int max_cost = 0;
    int min_cost = 100000;
    Edge e;

    for (int i = start; i < M; i++)
    {
        e = edges[i];
        if (!uft.isSame(e.u, e.v))
        {
            uft.unite(e.u, e.v);
            max_cost = max(max_cost, e.cost);
            min_cost = min(min_cost, e.cost);
        }
    }
    for (int i = 0; i < start; i++)
    {
        e = edges[i];
        if (!uft.isSame(e.u, e.v))
        {
            uft.unite(e.u, e.v);
            max_cost = max(max_cost, e.cost);
            min_cost = min(min_cost, e.cost);
        }
    }
    if (uft.size[uft.findRoot(0)] != N)
        return -1;
    else
        return max_cost - min_cost;
}

int main()
{
    int N, M;
    int a, b, w;

    while (cin >> N >> M)
    {
        if (N == 0 && M == 0)
            break;
        else if (M == 0)
            cout << -1 << endl;
        else
        {

            vector<Edge> edges;
            for (int i = 0; i < M; i++)
            {
                cin >> a >> b >> w;
                Edge e = {a - 1, b - 1, w};
                edges.push_back(e);
            }
            sort(edges.begin(), edges.end(), comp_e);

            int min_slimness = 100000;
            for (int i = 0; i < M; i++)
            {
                min_slimness = min(min_slimness, kruskal(edges, N, M, i));
                if (min_slimness == -1)
                    break;
            }

            cout << min_slimness << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 3596
final_rank: 18