use std::{ io::Write, io::{BufWriter, read_to_string, stdin, stdout}, }; fn init_tree( tree: &mut Vec<(u64, u64)>, arr: &Vec, i: usize, l: usize, r: usize, ) -> (u64, u64) { if l == r { tree[i] = (arr[l], arr[l]); return (arr[l], arr[l]); } let m = (l + r) / 2; let (m1, x1) = init_tree(tree, arr, i * 2 + 1, l, m); let (m2, x2) = init_tree(tree, arr, 2 * i + 2, m + 1, r); tree[i] = (m1.min(m2), x1.max(x2)); return tree[i]; } fn query( tree: &mut Vec<(u64, u64)>, i: usize, l: usize, r: usize, ql: usize, qr: usize, ) -> (u64, u64) { if r < ql || l > qr { (u64::MAX, u64::MIN) } else if ql <= l && r <= qr { tree[i] } else { let m = (l + r) / 2; let (m1, x1) = query(tree, 2 * i + 1, l, m, ql, qr); let (m2, x2) = query(tree, 2 * i + 2, m + 1, r, ql, qr); (m1.min(m2), x1.max(x2)) } } fn main() { let temp = read_to_string(stdin()).unwrap(); let mut iter = temp .split_ascii_whitespace() .map(|x| x.parse::().unwrap()); let (n, m) = (iter.next().unwrap() as usize, iter.next().unwrap() as usize); let arr = (0..n) .map(|_| iter.next().unwrap() as u64) .collect::>(); let mut tree = vec![(0, 0); 4 * n]; init_tree(&mut tree, &arr, 0, 0, n - 1); let mut out = BufWriter::new(stdout()); for _ in 0..m { let (i, j) = ( iter.next().unwrap() as usize - 1, iter.next().unwrap() as usize - 1, ); let (rm, rx) = query(&mut tree, 0, 0, n - 1, i, j); write!(out, "{} {}\n", rm, rx).unwrap(); } }