use std::collections::BinaryHeap; use std::cmp::Reverse; const INF: u32 = 1 << 30; fn run<'a, I: Iterator>(mut scanner: I) { macro_rules! scan { ([$t:tt; $n:expr]) => ((0..$n).map(|_| scan!($t)).collect::>()); (($($t:tt),*)) => (($(scan!($t)),*)); ([$($t:tt),*]) => ([$(scan!($t)),*]); (Usize1) => (scan!(usize) - 1); (Bytes) => (scan!(String).into_bytes()); ($t:ty) => (scanner.next().unwrap().parse::<$t>().unwrap()); } macro_rules! input { ($($($v:ident)* : $t:tt),* $(,)?) => ($(let $($v)* = scan!($t);)*); } input! { n: usize, m: usize, } let mut g = vec![vec![]; n]; for _ in 0..m { input! { s: Usize1, t: Usize1, d: u32, } g[s].push((t, d)); g[t].push((s, d)); } let (mut l, mut r) = (0, INF); while r - l > 1 { let w = (l + r) / 2; let mut stack = Vec::new(); stack.push(0); let mut used = vec![false; n]; used[0] = true; while let Some(from) = stack.pop() { for &(to, d) in &g[from] { if w > d || used[to] { continue; } stack.push(to); used[to] = true; } } if *used.last().unwrap() { l = w; } else { r = w; } } let w = l; let mut dist = vec![INF; n]; let mut heap = BinaryHeap::new(); dist[0] = 0; heap.push((Reverse(0), 0)); while let Some((Reverse(cost), from)) = heap.pop() { if dist[from] < cost { continue; } for &(to, d) in &g[from] { if w > d { continue; } let next_cost = cost + 1; if next_cost < dist[to] { dist[to] = next_cost; heap.push((Reverse(next_cost), to)); } } } println!("{} {}", w, dist.last().unwrap()); } fn main() { let ref mut buf = Vec::new(); std::io::Read::read_to_end(&mut std::io::stdin(), buf).ok(); run(std::str::from_utf8(buf).unwrap().split_whitespace()); }