Problem:
Problem Statement
You are given a connected undirected graph which has even numbers of nodes.
A connected graph is a graph in which all nodes are connected directly or indirectly by  edges.
Your task is to find a spanning tree whose median value of edges' costs is  minimum.
A spanning tree of a graph means that a tree which contains all nodes of the graph.
Input
The input consists of multiple  datasets.
The format of each dataset is as follows.
n
m
s_1
t_1
c_1
...
s_m
t_m
c_m
The first line contains an even number
n
(
2 \leq n \leq 1,000
) and an integer
m
(n-1 \leq m \leq 10,000)
.
n
is the nubmer of nodes and
m
is the number of edges in the graph.
Then
m
lines follow, each of which contains
s_i
(
1 \leq s_i \leq n
),
t_i
(
1 \leq s_i \leq n, t_i \neq s_i
) and
c_i
(
1 \leq c_i \leq 1,000
).
This means there is an edge between the nodes
s_i
and
t_i
and its cost is
c_i
.
There is no more than one edge which connects
s_i
and
t_i
.
The input terminates when
n=0
and
m=0
.
Your program must not output anything for this case.
Output
Print the median value in a line for each dataset.
Sample Input
2 1
1 2 5
4 6
1 2 1
1 3 2
1 4 3
2 3 4
2 4 5
3 4 6
8 17
1 4 767
3 1 609
8 3 426
6 5 972
8 1 607
6 4 51
5 1 683
3 6 451
3 4 630
8 7 912
3 7 43
4 7 421
3 5 582
8 4 538
5 7 832
1 6 345
8 2 608
0 0
Output for the Sample Input
5
2
421

Submitted solutions:

code_snippet: /*
Author: 1412kid1412@UESTC
*/

#include <stdexcept>
#include <cstdarg>
#include <iostream>
#include <fstream>
#include <exception>
#include <memory>
#include <locale>
#include <sstream>
#include <set>
#include <list>
#include <bitset>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <string>
#include <utility>
#include <cctype>
#include <climits>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <map>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <deque>
#include <cstdlib>
#include <stack>
#include <iterator>
#include <functional>
#include <complex>
#include <valarray>
using namespace std;

struct Record{
	int x,y,w;
	Record(){
	}
	Record(int x,int y,int w):x(x),y(y),w(w){
	}
	bool operator<(const Record& re)const{
		return w<re.w;
	}
};
Record re[10010];

int p[1010];
int f(int x){
	return x==p[x]?x:p[x]=f(p[x]);
}

int main(){
	int n,m;
	while(scanf("%d%d",&n,&m)){
		if(0==n&&0==m)break;
		for(int i=0;i<m;i++){
			scanf("%d%d%d",&re[i].x,&re[i].y,&re[i].w);
		}
		sort(re,re+m);
		for(int i=0;i<m;i++){
			for(int j=1;j<=n;j++){
				p[j]=j;
			}
			int fx=f(re[i].x);
			int fy=f(re[i].y);
			if(fx!=fy){
				p[fx]=fy;
			}
			int cnt1=0,cnt2=0;
			for(int j=0;j<i&&cnt1<n/2-1;j++){
				fx=f(re[j].x);
				fy=f(re[j].y);
				if(fx!=fy){
					p[fx]=fy;
					cnt1++;
				}
			}
			for(int j=i+1;j<m&&cnt2<n/2-1;j++){
				fx=f(re[j].x);
				fy=f(re[j].y);
				if(fx!=fy){
					p[fx]=fy;
					cnt2++;
				}
			}
			if(cnt1==n/2-1&&cnt2==n/2-1){
				printf("%d\n",re[i].w);
				break;
			}
		}
	}
	return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 3588
final_rank: 13

code_snippet: #include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <string>

using namespace std;

const int MAXN=1050, MAXM=10050;
int u[MAXM],v[MAXM],w[MAXM];
bool used[MAXM];
int lens[MAXM], ll;

int m, n;

void addedge(int x, int y, int len)
{
    u[m]=x, v[m]=y, w[m]=len;
    m++;
}

int parent[MAXN], rank1[MAXM];     // parent代表并查集，rank是边的序号
bool comp (const int i, const int j) {return w[i]<w[j];}

int find (int x)    // `带路径压缩的查找函数`
{
    return parent[x]==x ? x : parent[x] = find(parent[x]);
}

int Kruskal()
{
    memset(used,false,sizeof(used));
    // 初始化并查集
    for (int i=0;i<n;i++) parent[i]=i;
    for (int i=0;i<m;i++) rank1[i]=i;
    // 按照边的权值大小排序，这样先进行循环的就是最短的边
    sort(rank1, rank1+m, comp);
    for (int i=0;i<m;i++)
    {
        int e=rank1[i];
        int x=find(u[e]), y=find(v[e]); // 找出当前边的两个端点所在集合的编号
        if (x!=y)   // 如果不在同一集合,合并
        {
            used[e]=true;
            parent[x] = y;
        }
    }
    return 0;
}

int main()
{
    //freopen("fuck.in","r",stdin);
    int M;
    while (scanf("%d%d",&n,&M)!=EOF and n!=0)
    {
        m=0;
        while (M--)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            x-=1,y-=1;
            addedge(x,y,z);

        }
        Kruskal();
        ll=0;
        for (int i=0; i<m; i++) if (used[i]) lens[ll++]=w[i];
        sort(lens,lens+ll);

        //for (int i=0; i<ll; i++) printf("%d ",lens[i]);
        //printf("\n");
        printf("%d\n",lens[n/2-1]);

    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3624
final_rank: 12

code_snippet: #include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

const int MAXN=10050, MAXM=100050;
int u[MAXM],v[MAXM],w[MAXM];
bool used[MAXM];
int lens[MAXM], ll;

int m, n;

void addedge(int x, int y, int len)
{
    u[m]=x, v[m]=y, w[m]=len;
    m++;
}

int parent[MAXN], rank1[MAXM];     // parent代表并查集，rank是边的序号
bool comp (const int i, const int j) {return w[i]<w[j];}

int find (int x)    // `带路径压缩的查找函数`
{
    return parent[x]==x ? x : parent[x] = find(parent[x]);
}

int Kruskal()
{
    memset(used,false,sizeof(used));
    // 初始化并查集
    for (int i=0;i<n;i++) parent[i]=i;
    for (int i=0;i<m;i++) rank1[i]=i;
    // 按照边的权值大小排序，这样先进行循环的就是最短的边
    sort(rank1, rank1+m, comp);
    for (int i=0;i<m;i++)
    {
        int e=rank1[i];
        int x=find(u[e]), y=find(v[e]); // 找出当前边的两个端点所在集合的编号
        if (x!=y)   // 如果不在同一集合,合并
        {
            used[e]=true;
            parent[x] = y;
        }
    }
    return 0;
}

int main()
{
    //freopen("fuck.in","r",stdin);
    int M;
    while (scanf("%d%d",&n,&M) , n!=0)
    {
        m=0;
        while (M--)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            x-=1,y-=1;
            addedge(x,y,z);
        }
        Kruskal();
        ll=0;
        for (int i=0; i<m; i++) if (used[i]) lens[ll++]=w[i];
        sort(lens,lens+ll);
        //for (int i=0; i<ll; i++) printf("%d ",lens[i]);
        //printf("\n");
        printf("%d\n",lens[n/2-1]);

    }

    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3728
final_rank: 15

code_snippet: #include <iostream>
#include <iomanip>
#include <cassert>
#include <vector>
#include <algorithm>
#include <utility>
#include <numeric>
#include <tuple>
// #include "Src/Number/IntegerDivision.hpp"
// #include "Src/Utility/BinarySearch.hpp"
// #include "Src/Sequence/CompressedSequence.hpp"
// #include "Src/Sequence/RunLengthEncoding.hpp"
// #include "Src/Algebra/Group/AdditiveGroup.hpp"
// #include "Src/DataStructure/FenwickTree/FenwickTree.hpp"
// using namespace zawa;
// #include "atcoder/modint"
// using mint = atcoder::modint998244353;
struct DSU {
    std::vector<int> par, sz;
    int allsz = 0;
    DSU(int n) : par(n), sz(n, 1), allsz(n) {
        std::iota(par.begin(), par.end(), 0);
    }
    int leader(int v) {
        assert(0 <= v and v < (int)par.size());
        return v == par[v] ? v : par[v] = leader(par[v]);
    }
    bool same(int u, int v) {
        return leader(u) == leader(v);
    }
    bool merge(int u, int v) {
        u = leader(u), v = leader(v);
        if (u == v) return false;
        if (sz[u] > sz[v]) std::swap(u, v);
        allsz--;
        par[v] = u;
        sz[u] += sz[v];
        return true;
    }
    int size() {
        return allsz;
    }
};
bool solve() {
    int N, M;
    std::cin >> N >> M;
    if (N == 0 and M == 0) return false;
    std::vector<std::tuple<int, int, int>> E(M);
    for (auto& [c, u, v] : E) {
        std::cin >> u >> v >> c;
        u--; v--;
    }
    int ok = 1001, ng = 0;
    while (ok - ng > 1) {
        const int m = (ok + ng) / 2;
        DSU dsu(N);
        for (auto [c, u, v] : E) {
            if (c <= m) dsu.merge(u, v);
        }
        int need = dsu.size() - 1;
        int c0 = N - 1 - need;
        // std::cout << ok << ' ' << ng << std::endl;
        // std::cout << need << ' ' << m << std::endl;
        if (c0 >= N / 2) ok = m;
        else ng = m;
    }
    std::cout << ok << std::endl;
    return true;
}
int main() {
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    std::ios::sync_with_stdio(false);
    while (solve()) ;
}
accuracy: 1
time_ms: 10
memory_kb: 3584
final_rank: 10

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

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

		vector<tuple<int, int, int>> E(M);
		for(auto&[c, u, v] : E) cin >> u >> v >> c, u--, v--;
		sort(E.begin(), E.end());

		vector<vector<int>> G(N);
		vector<int> ws;
		for(auto [c, u, v] : E){
			queue<int> que;
			que.push(u);
			vector<bool> seen(N, false);
			seen[u] = true;
			while(!que.empty()){
				int now = que.front();
				que.pop();
				for(int nxt : G[now]){
					if(!seen[nxt]){
						seen[nxt] = true;
						que.push(nxt);
					}
				}
			}
			if(!seen[v]){
				ws.push_back(c);
				G[u].push_back(v);
				G[v].push_back(u);
			}
		}

		cout << ws[N/2-1] << '\n';
	}
}
accuracy: 1
time_ms: 510
memory_kb: 3240
final_rank: 19

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
 */

int main() {
while(1) {
    int N, M;
    cin >> N >> M;
    if (N == 0) return 0;
    vector<pair<int,pair<int,int>>> V;
    rep(i,0,M) {
        int S, T, C;
        cin >> S >> T >> C;
        S--, T--;
        V.push_back({C,{S,T}});
    }
    sort(ALL(V));
    UnionFind UF(N);
    vector<int> ANS;
    rep(i,0,M) {
        if (!UF.same(V[i].second.first,V[i].second.second)) {
            ANS.push_back(V[i].first);
            UF.unite(V[i].second.first,V[i].second.second);
        }
    }
    cout << ANS[N/2-1] << endl;
}
}
accuracy: 1
time_ms: 40
memory_kb: 3364
final_rank: 6

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

using namespace std;
//make -f ../makefile SRC=

/*
*/
//------------------------------------------------------------------------------
bool DEBUG = false;

const int MAX_N = 1000;
//static int vect[MAX_N];

struct SEdge
{
    int v, w, c;
    bool operator<(const SEdge& other) const
    {
        return c < other.c;
    }

    SEdge(): v(-1), w(-1), c(-1) {}
    SEdge(int v1, int v2, int cost): v(v1), w(v2), c(cost) {}
    void debug() const { printf("(%d, %d, %d)\n", v, w, c); }
};

typedef vector<SEdge> SEdges;

//------------------------------------------------------------------------------
class QuickUnion
{
    public:
    int N;
    int M; // no. of edges
    int* parent;
    int* count_; // no. of nodes rooted at n
    QuickUnion(int num): N(num), M(0)
    {
        parent = new int[N]; // 0-based nodes
        count_ = new int[N];
        for (int n=0; n<N; n++) { parent[n]=n; count_[n]=1; }
    }

    ~QuickUnion() { delete[] parent; delete[] count_; }

    int size(int n) //<--------------------
    {
        int p = root(n);
        return count_[p];
    }

    bool connected()
    {
        return M+1 >= N;
    }

    bool unite(int n1, int n2) //<---------- return true if action is successful
    {
        int r1 = root(n1);
        int r2 = root(n2);
        if (r1==r2) return false;
        M++; //<---------- for checking whether all are connected

        if (count_[r1] < count_[r2]) { parent[r1] = r2; count_[r2] += count_[r1]; }
        else { parent[r2] = r1; count_[r1] += count_[r2]; }
        return true;
    }

    bool find(int n1, int n2)
    {
        return root(n1)==root(n2);
    }

    int root(int node)
    {
        int n = node;
        while (n != parent[n])
        {
            parent[n] = parent[parent[n]]; // vs compression
            n = parent[n];
        }
        parent[node] = n;
        return n;
    }

    void debug() const
    {
        for (int n=0; n<N; n++) printf("node=%d, root=%d\n", n, parent[n]);
        printf("\n");
    }
};

//------------------------------------------------------------------------------
int kruskal(int N, SEdges& edges)
{
    vector<int> R;
    QuickUnion QU(N);
    sort(edges.begin(), edges.end());
    for (SEdge e: edges)
    {
        if (QU.connected()) break;
        if (QU.unite(e.v, e.w))
        {
            if (DEBUG) printf("e.c=%d\n", e.c);
            R.push_back( e.c );
        }
    }
    //--------------------------------------------------------------------------
    sort(R.begin(), R.end());
    int K = R.size();
    if (K%2 == 1) return R[K/2];
    return (R[K/2-1]+R[K/2])/2;
}

//------------------------------------------------------------------------------
void test()
{

}

//------------------------------------------------------------------------------
int main()
{
    //DEBUG = true;
    //test(); return 0;
    //--------------------------------------------------------------------------
    int N, M, v, w, c, num;
    while (true)
    {
        num = scanf("%d %d ", &N, &M);
        if (N == 0 && M == 0) break;
        SEdges E(M);
        for (int m=0; m<M; ++m)
        {
            num = scanf("%d %d %d ", &v, &w, &c);
            v--;
            w--;
            E[m] = SEdge(v, w, c);
        }
        int res = kruskal(N, E);
        printf("%d\n", res);
    }

    return 0;
}

//------------------------------------------------------------------------------
accuracy: 1
time_ms: 10
memory_kb: 3620
final_rank: 11

code_snippet: #line 1 "a.cpp"
#define PROBLEM ""
#line 2 "/home/kuhaku/home/github/algo/lib/template/template.hpp"
#pragma GCC target("sse4.2,avx2,bmi2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
template <class T, class U>
bool chmax(T &a, const U &b) {
    return a < (T)b ? a = (T)b, true : false;
}
template <class T, class U>
bool chmin(T &a, const U &b) {
    return (T)b < a ? a = (T)b, true : false;
}
constexpr std::int64_t INF = 1000000000000000003;
constexpr int Inf = 1000000003;
constexpr int MOD = 1000000007;
constexpr int MOD_N = 998244353;
constexpr double EPS = 1e-7;
constexpr double PI = M_PI;
#line 3 "/home/kuhaku/home/github/algo/lib/template/macro.hpp"
#define FOR(i, m, n) for (int i = (m); i < int(n); ++i)
#define FORR(i, m, n) for (int i = (m)-1; i >= int(n); --i)
#define FORL(i, m, n) for (int64_t i = (m); i < int64_t(n); ++i)
#define rep(i, n) FOR (i, 0, n)
#define repn(i, n) FOR (i, 1, n + 1)
#define repr(i, n) FORR (i, n, 0)
#define repnr(i, n) FORR (i, n + 1, 1)
#define all(s) (s).begin(), (s).end()
#line 3 "/home/kuhaku/home/github/algo/lib/template/sonic.hpp"
struct Sonic {
    Sonic() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
    }

    constexpr void operator()() const {}
} sonic;
#line 5 "/home/kuhaku/home/github/algo/lib/template/atcoder.hpp"
using namespace std;
using ll = std::int64_t;
using ld = long double;
template <class T, class U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {
    return is >> p.first >> p.second;
}
template <class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
    for (T &i : v) is >> i;
    return is;
}
template <class T, class U>
std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &p) {
    return os << '(' << p.first << ',' << p.second << ')';
}
template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
    for (auto it = v.begin(); it != v.end(); ++it) {
        os << (it == v.begin() ? "" : " ") << *it;
    }
    return os;
}
template <class Head, class... Tail>
void co(Head &&head, Tail &&...tail) {
    if constexpr (sizeof...(tail) == 0) std::cout << head << '\n';
    else std::cout << head << ' ', co(std::forward<Tail>(tail)...);
}
template <class Head, class... Tail>
void ce(Head &&head, Tail &&...tail) {
    if constexpr (sizeof...(tail) == 0) std::cerr << head << '\n';
    else std::cerr << head << ' ', ce(std::forward<Tail>(tail)...);
}
template <typename T, typename... Args>
auto make_vector(T x, int arg, Args... args) {
    if constexpr (sizeof...(args) == 0) return std::vector<T>(arg, x);
    else return std::vector(arg, make_vector<T>(x, args...));
}
void setp(int n) {
    std::cout << std::fixed << std::setprecision(n);
}
void Yes(bool is_correct = true) {
    std::cout << (is_correct ? "Yes" : "No") << '\n';
}
void No(bool is_not_correct = true) {
    Yes(!is_not_correct);
}
void YES(bool is_correct = true) {
    std::cout << (is_correct ? "YES" : "NO") << '\n';
}
void NO(bool is_not_correct = true) {
    YES(!is_not_correct);
}
void Takahashi(bool is_correct = true) {
    std::cout << (is_correct ? "Takahashi" : "Aoki") << '\n';
}
void Aoki(bool is_not_correct = true) {
    Takahashi(!is_not_correct);
}
#line 2 "/home/kuhaku/home/github/algo/lib/tree/union_find.hpp"

/**
 * @brief 素集合データ構造
 * @details Implement (union by size) + (path compression)
 * @see https://github.com/atcoder/ac-library/blob/master/atcoder/dsu.hpp
 */
struct union_find {
    union_find() : data() {}
    union_find(int _n) : data(_n, -1) {}

    int root(int x) { return this->data[x] < 0 ? x : this->data[x] = this->root(this->data[x]); }
    int get_root(int x) { return this->root(x); }

    bool is_root(int x) const { return this->data[x] < 0; }

    bool same(int x, int y) { return this->root(x) == this->root(y); }
    bool is_same(int x, int y) { return this->same(x, y); }

    int size(int x) { return -(this->data[this->root(x)]); }
    int get_size(int x) { return this->size(x); }

    bool unite(int x, int y) {
        x = this->root(x), y = this->root(y);
        if (x == y) return false;
        if (this->data[x] > this->data[y]) std::swap(x, y);
        this->data[x] += this->data[y];
        this->data[y] = x;
        return true;
    }

    template <class F>
    bool unite(int x, int y, F f) {
        x = this->root(x), y = this->root(y);
        if (x != y) {
            if (this->data[x] > this->data[y]) std::swap(x, y);
            this->data[x] += this->data[y];
            this->data[y] = x;
        }
        f(x, y);
        return x != y;
    }

  private:
    std::vector<int> data;
};
#line 4 "a.cpp"

int main(void) {
    while (true) {
        int n, m;
        cin >> n >> m;
        if (!n)
            break;
        vector<tuple<int, int, int>> edges;
        rep (i, m) {
            int u, v, c;
            cin >> u >> v >> c;
            edges.emplace_back(u - 1, v - 1, c);
        }
        sort(all(edges), [](auto l, auto r) {
            return get<2>(l) < get<2>(r);
        });

        int c = 0;
        union_find uf(n);
        for (auto [u, v, d] : edges) {
            if (uf.unite(u, v)) {
                ++c;
                if (c == n / 2) {
                    co(d);
                    break;
                }
            }
        }
    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3312
final_rank: 2

code_snippet: #pragma region template
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
#ifdef __LOCAL
 #include <debug>
#else
 #define debug(...) void(0)
#endif

using ll=long long;
using ld=long double;
using vi=vector<int>;
using vll=vector<ll>;
using pi=pair<int,int>;
using pll=pair<ll,ll>;

#define overload2(a,b,c,...) c
#define overload3(a,b,c,d,...) d
#define overload4(a,b,c,d,e,...) e
#define overload5(a,b,c,d,e,f,...) f

#define TYPE1(T) template<typename T>
#define TYPE2(T,U) template<typename T,typename U>
#define TYPE(...) overload2(__VA_ARGS__,TYPE2,TYPE1)(__VA_ARGS__)
#define TYPES1(T) template<typename... T>
#define TYPES2(H,T) template<typename H,typename... T>
#define TYPES(...) overload2(__VA_ARGS__,TYPES2,TYPES1)(__VA_ARGS__)

#define REP4(i,s,n,d) for(ll i=(s);i<(n);i+=(d))
#define REP3(i,s,n) REP4(i,s,n,1)
#define REP2(i,n) REP3(i,0,n)
#define REP1(n) REP2(tomato,n)
#define REP(...) overload4(__VA_ARGS__,REP4,REP3,REP2,REP1)(__VA_ARGS__)

#define RREP4(i,s,n,d) for(ll i=(n)-1;i>=s;i-=d)
#define RREP3(i,s,n) RREP4(i,s,n,1)
#define RREP2(i,n) RREP3(i,0,n)
#define RREP1(n) RREP2(tomato,n)
#define RREP(...) overload4(__VA_ARGS__,RREP4,RREP3,RREP2,RREP1)(__VA_ARGS__)

#define ALL(v) v.begin(),v.end()
#define RALL(v) v.rbegin(),v.rend()
#define SORT(v) sort(ALL(v))
#define RSORT(v) sort(RALL(v))
#define REVERSE(v) reverse(ALL(v))
#define UNIQUE(v) SORT(v),v.erase(unique(ALL(v)),v.end())

TYPES(T) void input(T&... a){ (cin>>...>>a); }
#define DECLARE(T,...) T __VA_ARGS__;input(__VA_ARGS__);
#define INT(...) DECLARE(int,__VA_ARGS__)
#define STR(...) DECLARE(string,__VA_ARGS__)
#define LL(...) DECLARE(long long,__VA_ARGS__)
#define CHR(...) DECLARE(char,__VA_ARGS__)
#define DBL(...) DECLARE(double,__VA_ARGS__)

TYPE(T)
istream&operator>>(istream&is,vector<T>&v){
  for(auto&a:v)cin>>a;
  return is;
}
TYPE(T)
ostream&operator<<(ostream&os,vector<T>&v){
  if(&os==&cerr)os<<"[";
  REP(i,v.size()){
    os<<v[i];
    if(i+1<v.size())os<<(&os==&cerr?",":" ");
  }
  if(&os==&cerr)os<<"]";
  return os;
}

#pragma endregion template

//BEGIN CUT HERE
struct UnionFind{
  int num;
  vector<int> r,p;
  UnionFind(){}
  UnionFind(int n):num(n),r(n,1),p(n,0){iota(p.begin(),p.end(),0);}
  
  int find(int x){
    return (x==p[x]?x:p[x]=find(p[x]));
  }
  
  bool same(int x,int y){
    return find(x)==find(y);
  }
  
  bool merge(int x,int y){
    x=find(x);y=find(y);
    if(x==y)return false;
    if(r[x]<r[y]) swap(x,y);
    r[x]+=r[y];
    p[y]=x;
    num--;
    return true;
  }
  
  int size(int x){
    return r[find(x)];
  }
  
  int count() const{
    return num;
  }
};
//END CUT HERE

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

  int n,m;
  while(cin>>n>>m,n){
    UnionFind uf(n);
    vector<tuple<int,int,int>> v(m);
    REP(i,m){
      INT(s,t,c);s--;t--;
      v[i]={c,s,t};
    }
    SORT(v);
    int cnt=0;
    int ans;
    for(auto&[c,s,t]:v){
      if(uf.same(s,t))continue;
      uf.merge(s,t);
      cnt++;
      if(cnt*2>n-1){
        ans=c;
        break;
      }
    }
    cout<<ans<<"\n";
  }
}
accuracy: 1
time_ms: 20
memory_kb: 3272
final_rank: 1

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 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;
}
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;
    }
    int merge(pair<ll,ll> p) {
        int a=p.first-1;
        int b=p.second-1;
        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);
    }
    bool same(pair<ll,ll> p) {
        int a=p.first-1;
        int b=p.second-1;
        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(){

    while(1){
        ll N,M;
        cin>>N>>M;
        if(N==0)return 0;
        vector<pair<ll,pair<ll,ll>>> E(M);
        rep(i,M)cin>>E[i].second.first>>E[i].second.second>>E[i].first;
        sort(all(E));
        vll U(N+M,0);
        dsu d(N);
        ll k=0;
        rep(i,M){
            if(!d.same(E[i].second)){
                U[k]=E[i].first;
                k++;
                d.merge(E[i].second);
            }
        }
        cout<<U[N/2-1]<<endl;
    }
}
accuracy: 1
time_ms: 40
memory_kb: 3392
final_rank: 8

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

#ifdef _RUTHEN
#include "debug.hpp"
#else
#define show(...) true
#endif

using ll = long long;
#define rep(i, n) for (int i = 0; i < (n); i++)
template <class T> using V = vector<T>;

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int N, M;
    while (cin >> N >> M, !(N == 0 and M == 0)) {
        V<tuple<ll, int, int>> es(M);
        rep(i, M) {
            int a, b, c;
            cin >> a >> b >> c;
            a--, b--;
            es[i] = {c, a, b};
        }
        sort(es.begin(), es.end());
        UnionFind uf(N);
        int cnt = 0, ans = -1;
        for (auto [c, a, b] : es) {
            if (uf.same(a, b)) continue;
            uf.merge(a, b);
            cnt++;
            if (cnt == N / 2) ans = c;
        }
        cout << ans << '\n';
    }
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3380
final_rank: 5

code_snippet: // #include "atcoder/all"
#include <iostream> // cout, endl, cin
#include <string> // string, to_string, stoi
#include <vector> // vector
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <utility> // pair, make_pair
#include <tuple> // tuple, make_tuple
#include <cstdint> // int64_t, int*_t
#include <cstdio> // printf
#include <map> // map
#include <queue> // queue, priority_queue
#include <set> // set
#include <stack> // stack
#include <deque> // deque
#include <unordered_map> // unordered_map
#include <unordered_set> // unordered_set
#include <bitset> // bitset
#include <cctype> // isupper, islower, isdigit, toupper, tolower
#include <iomanip> // setprecision
#include <complex> // complex
#include <math.h>
#include <functional>
#include <cassert>
using namespace std;
// using namespace atcoder;
using ll = long long;
using P = pair<ll,ll>;
constexpr ll INF = 1e18;
constexpr ll LLMAX = 9223372036854775807;
constexpr int inf = 1e9;
// constexpr ll mod = 1000000007;
constexpr ll mod = 998244353;
// 右下左上
const int dx[8] = {1, 0, -1, 0,1,1,-1,-1};
const int dy[8] = {0, 1, 0, -1,1,-1,1,-1};
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
ll gcd(ll a,ll b){if(b==0){return a;}else{return gcd(b,a%b);}};
#define eb emplace_back
#define pb pop_back
#define eol endl
// ---------------------------------------------------------------------------


struct UnionFind {
    vector<int> par, w;

    UnionFind(int n) : par(n, -1), w(n, 0) { }
    void init(int n) { par.assign(n, -1); w.assign(n, 0); }

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

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

    bool merge(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) {
            ++w[x];
            return false;
        }
        if (par[x] > par[y]) swap(x, y); // merge technique
        par[x] += par[y];
        par[y] = x;
        w[x] += w[y];
        ++w[x];
        return true;
    }

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

    int wei(int x) {
        return w[root(x)];
    }
};


bool solve(){
    ll N,M;
    cin >> N >> M;
    if(N == 0) return false;
    using tup = tuple<ll,ll,ll>;
    vector<tup> E;
    for(int i=0; i<M; i++){
        ll a,b,c;
        cin >> a >> b >> c;
        a--;b--;
        E.emplace_back(c,a,b);
    }
    sort(E.begin(),E.end());
    ll ng=0,ok=INF;
    while(ok-ng>1){
        ll m = (ok+ng)/2;
        UnionFind uf(N);
        ll num = 0;
        for(int i=0; i<M; i++){
            ll cost,a,b;
            tie(cost,a,b) = E[i];
            if(uf.issame(a,b)) continue;
            if(cost > m) break;
            num++;
            uf.merge(a,b);            
        }
        if(num >= N/2){
            ok = m;
        }else{
            ng = m;
        }
    }
    cout << ok << endl;
    return true;
}


int main(){
    while(solve());
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 3696
final_rank: 16

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 s,t,c; cin >> s >> t >> c; s--; t--;
            edges.push_back({c, s, t});
        }

        sort(edges.begin(), edges.end());
        union_find uf(n);
        vector<int> cs;
        for(auto [c, s, t] : edges) {
            if(uf.unite(s, t)) cs.push_back(c);
        }
        cout << cs[cs.size() / 2] << endl;
    }
}
accuracy: 1
time_ms: 20
memory_kb: 3308
final_rank: 3

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

using ll = long long;

// Union-Find Tree
struct UnionFind {
  vector<int> par; // 親のid(親の場合, 集合の頂点数の-1倍)
  
  UnionFind(int n): par(n, -1) {}
  
  void init(int n) {
    par.assign(n, -1);
  }
  
  int find(int x) {
    if (par[x] < 0) return x;
    return par[x] = find(par[x]);
  }
  
  bool unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return false;
    if (par[x] > par[y]) swap(x, y);
    par[x] += par[y];
    par[y] = x;
    return true;
  }
  
  bool same(int x, int y) {
    return find(x) == find(y);
  }
  
  int size(int x) {
    return -par[find(x)];
  }
};


// クラスカル法(Union-Findと同時に使う) O(ElogE)
vector<tuple<ll, int, int>> kruskal(const vector<vector<pair<int, ll>>> &G) {
  vector<tuple<ll, int, int>> x;
  for (int i = 0; i < G.size(); i++) {
    for (int j = 0; j < G[i].size(); j++) {
      x.emplace_back(make_tuple(G[i][j].second, i, G[i][j].first));
    }
  }
  sort(x.begin(), x.end());
  UnionFind uf(G.size());
  ll cost = 0;
  vector<tuple<ll, int, int>> MST; // 最小全域木
  for (int i = 0; i < x.size(); i++) {
    if (uf.unite(get<1>(x.at(i)), get<2>(x.at(i)))) {
      cost += get<0>(x.at(i));
      MST.emplace_back(make_tuple(get<0>(x.at(i)), get<1>(x.at(i)), get<2>(x.at(i))));
    }
  }
//  return cost;
  return MST;
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  while (true) {
    int n, m;
    cin >> n >> m;
    if (n + m == 0) return 0;

    vector<vector<pair<int, ll>>> G(n);
    for (int i = 0; i < m; i++) {
      int s, t;
      ll c;
      cin >> s >> t >> c;
      s--;
      t--;
      G[s].emplace_back(make_pair(t, c));
      G[t].emplace_back(make_pair(s, c));
    }

    vector<tuple<ll, int, int>> x = kruskal(G);
    sort(x.begin(), x.end());
    cout << get<0>(x.at(n / 2 - 1)) << '\n';
  }
}
accuracy: 1
time_ms: 30
memory_kb: 4360
final_rank: 20

code_snippet: // #include "atcoder/all"
#include <iostream> // cout, endl, cin
#include <string> // string, to_string, stoi
#include <vector> // vector
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <utility> // pair, make_pair
#include <tuple> // tuple, make_tuple
#include <cstdint> // int64_t, int*_t
#include <cstdio> // printf
#include <map> // map
#include <queue> // queue, priority_queue
#include <set> // set
#include <stack> // stack
#include <deque> // deque
#include <unordered_map> // unordered_map
#include <unordered_set> // unordered_set
#include <bitset> // bitset
#include <cctype> // isupper, islower, isdigit, toupper, tolower
#include <iomanip> // setprecision
#include <complex> // complex
#include <math.h>
#include <functional>
#include <cassert>
using namespace std;
// using namespace atcoder;
using ll = long long;
using P = pair<ll,ll>;
constexpr ll INF = 1e15;
constexpr ll LLMAX = 9223372036854775807;
constexpr int inf = 1e9;
// constexpr ll mod = 1000000007;
constexpr ll mod = 998244353;
// 右下左上
const int dx[8] = {1, 0, -1, 0,1,1,-1,-1};
const int dy[8] = {0, 1, 0, -1,1,-1,1,-1};
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
#define eol "\n"
// ---------------------------------------------------------------------------


struct UnionFind {
    vector<int> par, w;

    UnionFind(int n) : par(n, -1), w(n, 0) { }
    void init(int n) { par.assign(n, -1); w.assign(n, 0); }

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

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

    bool merge(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) {
            ++w[x];
            return false;
        }
        if (par[x] > par[y]) swap(x, y); // merge technique
        par[x] += par[y];
        par[y] = x;
        w[x] += w[y];
        ++w[x];
        return true;
    }

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

    int wei(int x) {
        return w[root(x)];
    }
};


bool solve(){
  int N,M;
  cin >> N >> M;
  if(N == 0) return false;
  UnionFind uf(N);
  using tup = tuple<ll,ll,ll>;
  vector<tup> vec;
  for(int i=0; i<M; i++){
    int a,b,c;
    cin >> a >> b >> c;
    a--;b--;
    vec.emplace_back(c,a,b);
  }
  sort(vec.begin(),vec.end());
  vector<ll> use;
  for(int i=0; i<M; i++){
    ll a,b,c;
    tie(c,a,b) = vec[i];
    if(!uf.issame(a,b)){
      uf.merge(a,b);
      use.emplace_back(c);
    }   
  }
  cout << use[N/2-1] << endl;
  return true;
}

int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  while(solve());
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3692
final_rank: 14

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

//Kruskal
const int MAX_E = 500000; //最大の辺の数

struct edge{
  int from;
  int to;
  int cost;
};

bool compare(const edge& e1, const edge& e2){
  return e1.cost < e2.cost;
}

vector<edge> G(0);

//UnionFind
int n = 100010; //最大の頂点数
vector<int> par(n);
vector<int> Size(n);

void init(int n){
  for(int i=0; i<n; i++){
    par.at(i) = i;
    Size.at(i) = 1;
  }
}

int root(int x){
  if(par.at(x) == x){
    return x;
  }
  else{
    return par.at(x) = root(par.at(x));
  }
}

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

void unite(int x, int y){
  x = root(x);
  y = root(y);
  if(x == y){
    return;
  }
  if (Size.at(x) < Size.at(y)){
    swap(x, y);
  }
  Size.at(x) += Size.at(y);
  par.at(y) = x;
}

int Size_x(int x){
  return Size.at(root(x));
}

int Kruskal(int N){
  sort(G.begin(), G.end(), compare);
  init(N);
  int res = 0;
  int cnt = 0;
  for(int i=0; i<G.size(); i++){
    edge e = G[i];
    if(!same(e.from, e.to)){
      unite(e.from, e.to);
      cnt++;
      if(cnt == N/2){
        res = e.cost;
      }
    }
  }
  return res;
}

void solve(int N){
  int M;
  cin >> M;
  G.clear();
  for(int i=0; i<M; i++){
    int a, b, c;
    cin >> a >> b >> c;
    a--; b--;
    //cout << a << " " << b << " " << c << endl;
    edge add = {a,b,c};
    G.push_back(add);
  }
  cout << Kruskal(N) << endl;
}

int main(){
  while(true){
    int N;
    cin >> N;
    if(N == 0){
      break;
    }
    solve(N);
    //break;
  }
}
accuracy: 1
time_ms: 40
memory_kb: 4116
final_rank: 18

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

const int INF = 1e9;
const long long inf = 1LL<<60;
using ll = long long;
template <class T>
struct Median {
private:
  int all_size = 0;
  multiset<T> left, right;
  T center = -1;
public:
  void add(T val) {
    if (all_size == 0) {
      center = val;
    } else {
      if (all_size & 1) {
        if (val <= center) {
          left.insert(val);
          right.insert(center);
        } else {
          right.insert(val);
          left.insert(center);
        }
        center = -1;
      } else {
        T L = *left.rbegin(), R = *right.begin();
        if (val <= L) {
          left.insert(val);
          center = L;
          left.erase(left.find(L));
        } else if (val <= R) {
          center = val;
        } else {
          right.insert(val);
          center = R;
          right.erase(right.find(R));
        }
      }
    }
    all_size++;
    return;
  }
  void del(T val) {
    assert(all_size > 0);
    bool change = false;
    if (all_size & 1) {
      if (center == val) {
        change = true;
      } else if (left.count(val)) {
        left.erase(left.find(val));
        left.insert(center);
        change = true;
      } else if (right.count(val)) {
        right.erase(right.find(val));
        right.insert(center);
        change = true;
      }
      center = -1;
    } else {
      if (left.count(val)) {
        left.erase(left.find(val));
        center = *right.begin();
        right.erase(right.find(center));
        change = true;
      } else if (right.count(val)) {
        right.erase(right.find(val));
        center = *left.rbegin();
        left.erase(left.find(center));
        change = true;
      }
    }
    assert(change);
    all_size--;
  }
  T query() {
    assert(all_size > 0);
    if (all_size & 1) return center;
    else {
      T L = *left.rbegin(), R = *right.begin();
      return (L+R)/(T)2;
    }
  }
  void dump() {
    for (auto u : left) cout << u << " ";
    if (all_size & 1) cout << center << " ";
    for (auto u : right) cout << u << " ";
    cout << endl;
  }
};
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;
};


bool solve() {
  int n, m; cin >> n >> m;
  if (n == 0) return 0;
  vector<vector<int>> edge(m, vector<int>(3));
  for (int i=0; i<m; i++) {
    int a, b, v; cin >> a >> b >> v;
    a--; b--;
    edge[i] = {v, a, b};
  }
  sort(edge.begin(), edge.end());
  dsu uf(n);
  Median<int> med;
  int cur = -1;
  while (uf.size(0) < n) {
    cur++;
    if (uf.same(edge[cur][1], edge[cur][2])) continue;
    uf.merge(edge[cur][1], edge[cur][2]);
    med.add(edge[cur][0]);
  }
  cout << med.query() << endl;
  return true;
}

int main() {
  while (solve());
}
accuracy: 1
time_ms: 50
memory_kb: 3728
final_rank: 17

code_snippet: #line 1 "main.cpp"
#pragma region Macros
#include <bits/stdc++.h>
using namespace std;
template <class T> inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T> inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif

struct Setup {
    Setup() {
        cin.tie(0);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
    }
} __Setup;

using ll = long long;
#define ALL(v) (v).begin(), (v).end()
#define RALL(v) (v).rbegin(), (v).rend()
#define FOR(i, a, b) for(int i = (a); i < int(b); i++)
#define REP(i, n) FOR(i, 0, n)
const int INF = 1 << 30;
const ll LLINF = 1LL << 60;
constexpr int MOD = 1000000007;

void Case(int i) { cout << "Case #" << i << ": "; }
int popcount(int x) { return __builtin_popcount(x); }
ll popcount(ll x) { return __builtin_popcountll(x); }
#pragma endregion Macros

#line 1 "/home/siro53/kyo-pro/compro_library/graph/dsu.hpp"
struct UnionFind {
    vector<int> par;

    UnionFind(int n) : par(n, -1) {}
    void init(int n) { par.assign(n, -1); }

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

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

    bool merge(int x, int y) {
        x = root(x);
        y = root(y);
        if(x == y)
            return false;
        if(par[x] > par[y])
            swap(x, y); // merge technique
        par[x] += par[y];
        par[y] = x;
        return true;
    }

    int size(int x) { return -par[root(x)]; }
};
#line 70 "main.cpp"

bool solve() {
    int N, M;
    cin >> N >> M;
    if(N == 0) return false;
    vector<tuple<int, int, int>> edges(M);
    REP(i, M) {
        int a, b, c;
        cin >> a >> b >> c;
        a--; b--;
        edges[i] = {c, a, b};
    }
    sort(ALL(edges));

    auto check = [&](int x) -> bool {
        UnionFind uf(N);
        int cnt = 0;
        REP(i, M) {
            auto [c, a, b] = edges[i];
            if(uf.issame(a, b)) continue;
            uf.merge(a, b);
            if(c <= x) cnt++;
        }
        if(uf.size(0) != N) return false;
        return (cnt >= N/2);
    };

    int ok = 1001, ng = 0;
    while(ok - ng > 1) {
        int mid = (ok + ng) / 2;
        (check(mid) ? ok : ng) = mid;
    }
    cout << ok << "\n";
    return true;
}

int main() {
    while(solve());
}
accuracy: 1
time_ms: 20
memory_kb: 3348
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>

#define rep(i, a, n) for (int i = (int)(a); i < (int)(n); i++)

using i64 = std::int64_t;

using graph = std::vector<std::vector<int>>;

#line 2 "data_structure/UnionFind.hpp"

#include <vector>

namespace ebi {

struct UnionFind {
private:
    std::vector<int> par;

public:
    UnionFind(int n=0): par(n,-1){ }

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

    bool merge(int x, int y){
        x = leader(x); y = leader(y);
        if(x==y) return false;
        if(par[x]>par[y]) std::swap(x,y);
        par[x]+=par[y];
        par[y] = x;
        return true;
    }

    int leader(int x){
        if(par[x]<0) return x;
        else return par[x] = leader(par[x]);
    }

    int size(int x){
        return -par[leader(x)];
    }

    int count_group(){
        int c = 0;
        for(int i = 0; i<int(par.size()); i++){
            if(par[i]<0) c++; 
        }
        return c;
    }
};

} // namespace ebi

int main() {
    int n,m;
    while(std::cin >> n >> m, n > 0 && m > 0) {
        ebi::UnionFind uf(n);
        std::vector<int> p;
        std::vector<int> s(m), t(m), c(m), idx(m);
        rep(i,0,m) {
            std::cin >> s[i] >> t[i] >> c[i];
            s[i]--; t[i]--;
            idx[i] = i;
        }
        std::sort(idx.begin(), idx.end(), [&](int i, int j) { return c[i] < c[j];});
        rep(i,0,m) {
            if(!uf.same(s[idx[i]], t[idx[i]])) {
                uf.merge(s[idx[i]], t[idx[i]]);
                p.emplace_back(c[idx[i]]);
            }
        }
        std::cout << p[n/2 - 1] << '\n';
    }
}
accuracy: 1
time_ms: 40
memory_kb: 3376
final_rank: 7

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

long long INF=1LL<<60;

//using namespace atcoder;
using namespace std;

struct edge{
    int to;
    long long weight;
    edge(int to,long long weight) : to(to),weight(weight){}
};

using Graph = vector<vector<edge>>;

struct Union_Find_Tree{
    std::vector<int> par;//親の番号
    std::vector<int> rank;//深さ
    Union_Find_Tree(int N) : par(N),rank(N) {//初期化
        for (int i=0; i<N; i++) {
            par[i]=i;
            rank[i]=0;
        }
    }
    
    int find(int x){//根を求める
        if (par[x]==x) {
            return x;
        }else{
            return par[x] = find(par[x]);
        }
    }
    
    void unite(int x,int y){//併合
        x=find(x);
        y=find(y);
        if (x==y) {
            return;
        }
        if (rank[x]<rank[y]) {
            par[x]=y;
        }else{
            par[y]=x;
            if (rank[x]==rank[y]) {
                rank[x]++;
            }
        }
    }
    
    bool same(int x,int y){//同じ根に属するか
        return find(x)==find(y);
    }
};

typedef long long ll;

int main(){
    vector<int> hoge;
    int V=-1,E=-1;
    while (V!=0 && E!=0) {
    scanf("%d %d",&V,&E);
    vector<pair<int, pair<int, int>>> edge(E);
    int s[E],t[E],w[E];
    for (int i=0; i<E; i++) {
        scanf("%d %d %d",&s[i],&t[i],&w[i]);
        edge[i]=pair<int, pair<int, int>>(w[i],make_pair(s[i], t[i]));
    }
    sort(edge.begin(), edge.end());
    Union_Find_Tree tree(V+1);
        vector<int> ans;
    for (int i=0; i<E; i++) {
        int s1=edge[i].second.first,t1=edge[i].second.second,w1=edge[i].first;
        if (tree.same(s1, t1)) {
            continue;
        }
        tree.unite(s1, t1);
        ans.push_back(w1);
    }
        if (V==0 && E==0) {
            break;
        }
        hoge.push_back(ans[ans.size()/2]);
    }
    for (int i=0; i<hoge.size(); i++) {
        cout << hoge[i] << endl;
    }
}
accuracy: 1
time_ms: 20
memory_kb: 3492
final_rank: 9