Problem:
Score : 600 points

Problem Statement

You are given a forest with N vertices and M edges. The vertices are numbered 0 through N-1.
The edges are given in the format (x_i,y_i), which means that Vertex x_i and y_i are connected by an edge.

Each vertex i has a value a_i.
You want to add edges in the given forest so that the forest becomes connected.
To add an edge, you choose two different vertices i and j, then span an edge between i and j.
This operation costs a_i + a_j dollars, and afterward neither Vertex i nor j can be selected again.

Find the minimum total cost required to make the forest connected, or print Impossible if it is impossible.

Constraints

1 ≤ N ≤ 100,000

0 ≤ M ≤ N-1

1 ≤ a_i ≤ 10^9

0 ≤ x_i,y_i ≤ N-1

The given graph is a forest.

All input values are integers.

Input

Input is given from Standard Input in the following format:

N M
a_0 a_1 .. a_{N-1}
x_1 y_1
x_2 y_2
:
x_M y_M

Output

Print the minimum total cost required to make the forest connected, or print Impossible if it is impossible.

Sample Input 1

7 5
1 2 3 4 5 6 7
3 0
4 0
1 2
1 3
5 6

Sample Output 1

7

If we connect vertices 0 and 5, the graph becomes connected, for the cost of 1 + 6 = 7 dollars.

Sample Input 2

5 0
3 1 4 1 5

Sample Output 2

Impossible

We can't make the graph connected.

Sample Input 3

1 0
5

Sample Output 3

0

The graph is already connected, so we do not need to add any edges.

Solution in Rust (1.42.0) (judge verdict: Wrong Answer)

#![allow(unused_imports)]
#![allow(unused_macros)]
use std::cmp::{max, min};
use std::collections::*;
use std::io::{stdin, Read};

#[allow(unused_macros)]
macro_rules! parse {
    ($it: ident ) => {};
    ($it: ident, ) => {};
    ($it: ident, $var:ident : $t:tt $($r:tt)*) => {
        let $var = parse_val!($it, $t);
        parse!($it $($r)*);
    };
    ($it: ident, mut $var:ident : $t:tt $($r:tt)*) => {
        let mut $var = parse_val!($it, $t);
        parse!($it $($r)*);
    };
}

#[allow(unused_macros)]
macro_rules! parse_val {
    ($it: ident, [$t:tt; $len:expr]) => {
        (0..$len).map(|_| parse_val!($it, $t)).collect::<Vec<_>>();
    };
    ($it: ident, ($($t: tt),*)) => {
        ($(parse_val!($it, $t)),*)
    };
    ($it: ident, u1) => {
        $it.next().unwrap().parse::<usize>().unwrap() -1
    };
    ($it: ident, $t: ty) => {
        $it.next().unwrap().parse::<$t>().unwrap()
    };
}

#[cfg(debug_assertions)]
macro_rules! debug {
    ($( $args:expr ),*) => { eprintln!( $( $args ),* ); }
}

#[cfg(not(debug_assertions))]
macro_rules! debug {
    ($( $args:expr ),*) => {
        ()
    };
}
use std::ops::{Add, Div};
pub fn binary_search<T: Add<Output = T> + Div<Output = T> + PartialEq + From<u8> + Copy>(
    l: T,
    r: T,
    pred: impl Fn(T) -> bool,
) -> T {
    let mut l = l;
    let mut r = r;
    let two = T::from(2_u8);
    loop {
        let m = (l + r) / two;
        if l == m || r == m {
            break l;
        }
        if pred(m) {
            l = m;
        } else {
            r = m;
        }
    }
}

#[test]
fn binary_search_test() {
    let v = [1, 2, 3, 4, 5];
    assert_eq!(3, binary_search(v.len() as _, -1, |i| v[i as usize] > 3));
    assert_eq!(5, binary_search(v.len() as _, -1, |i| v[i as usize] > 100));
    assert_eq!(0, binary_search(v.len() as _, -1, |i| v[i as usize] > 0));
}

/// Returns index to the first element in `v` which does not compare less than `val`.
pub fn lower_bound<T: PartialOrd>(v: &[T], val: &T) -> usize {
    (binary_search(-1, v.len() as i64, |i: i64| v[i as usize] < *val) + 1) as usize
}

#[test]
fn lower_bound_test() {
    let v: &[i32] = &[1, 3, 3, 4, 5];
    assert_eq!(lower_bound(v, &0), 0);
    assert_eq!(lower_bound(v, &1), 0);
    assert_eq!(lower_bound(v, &2), 1);
    assert_eq!(lower_bound(v, &3), 1);
    assert_eq!(lower_bound(v, &4), 3);
    assert_eq!(lower_bound(v, &5), 4);
    assert_eq!(lower_bound(v, &999), 5);
}

/// Returns index to the first element in `v` which compares greater than `val`.
pub fn upper_bound<T: PartialOrd>(v: &[T], val: &T) -> usize {
    (binary_search(-1, v.len() as i64, |i: i64| v[i as usize] <= *val) + 1) as usize
}

fn solve(s: &str) {
    let mut it = s.split_whitespace();
    parse!(it, n: usize, m: usize, a: [usize; n]);
    let a: Vec<usize> = a;
    let mut uf = UnionFind::new(n);
    for _ in 0..m {
        parse!(it, x: usize, y: usize);
        uf.union(x, y);
    }
    let mut _c = vec![BTreeSet::<(usize, usize)>::new(); n];
    for i in 0..n {
        _c[uf.root(i)].insert((a[i], i));
    }
    let mut c = BTreeMap::<(usize, usize), BTreeSet<(usize, usize)>>::new();
    let mut ones = vec![];
    for v in _c {
        if v.len() > 1 {
            let k = v.iter().next().unwrap();
            c.insert(*k, v);
        } else if let Some(x) = v.into_iter().next() {
            ones.push(x);
        }
    }
    let mut ret = 0;
    'outer: while ones.len() + c.len() > 1 {
        while let Some(x) = ones.pop() {
            if let Some((k, mut t)) = pop_first(&mut c) {
                // merge into c
                t.insert(x);
                ret += x.0 + k.0;

                // back t to map
                if t.len() > 1 {
                    let k = t.iter().next().unwrap();
                    c.insert(*k, t);
                } else if let Some(x) = t.into_iter().next() {
                    ones.push(x);
                } else if c.len() + ones.len() > 0 {
                    println!("{}", "Impossible");
                    return;
                } else {
                    break 'outer;
                }
            }
        }
        if c.len() == 1 {
            break;
        } else if c.len() == 0 {
            println!("{}", "Impossible");
            return;
        }
        if let Some((k0, mut t0)) = pop_first(&mut c) {
            if let Some((k1, mut t1)) = pop_first(&mut c) {
                ret += k0.0 + k1.0;
                t0.append(&mut t1);
                let &k = t0.iter().next().unwrap();
                if t0.len() > 1 {
                    c.insert(k, t0);
                } else if t0.len() == 1 {
                    ones.push(k);
                } else if c.len() + ones.len() > 0 {
                    println!("{}", "Impossible");
                    return;
                }
            }
        }
    }
    println!("{}", ret);
}

pub fn pop_first<K: std::cmp::Ord + Clone, V>(tree: &mut BTreeMap<K, V>) -> Option<(K, V)> {
    if let Some(k) = tree.keys().next() {
        let k = k.clone();
        let v = tree.remove(&k).unwrap();
        Some((k, v))
    } else {
        None
    }
}

pub struct UnionFind {
    pub parents: Vec<usize>,
}
impl UnionFind {
    pub fn new(n: usize) -> Self {
        let par = (0..n).collect();
        UnionFind { parents: par }
    }
    pub fn root(&mut self, x: usize) -> usize {
        if self.parents[x] == x {
            return x;
        }
        let par = self.parents[x];
        self.parents[x] = self.root(par);
        self.parents[x]
    }
    pub fn union(&mut self, x: usize, y: usize) {
        let rx = self.root(x);
        let ry = self.root(y);
        if rx == ry {
            return;
        }
        self.parents[rx] = ry;
    }
    pub fn is_same(&mut self, x: usize, y: usize) -> bool {
        let rx = self.root(x);
        let ry = self.root(y);
        rx == ry
    }
}

fn main() {
    let mut s = String::new();
    stdin().read_to_string(&mut s).unwrap();
    solve(&s);
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_input() {
        let s = "
        ";
        solve(s);
    }
}