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.15.1) (judge verdict: Accepted)

use std::io::{stdin, Read, StdinLock};
use std::str::FromStr;
use std::iter::FromIterator;
use std::collections::BinaryHeap;

fn main() {
    let cin = stdin();
    let mut scan = Scanner::new(cin.lock());
    let n = scan.read::<usize>();
    let m = scan.read::<usize>();
    let a = scan.readn::<i64>(n);
    let e = arr(m, |_| (scan.read::<usize>(), scan.read::<usize>()));
    let mut utree = Utree::new(n);
    let mut g = n;
    for (s, t) in e {
        if !utree.is_same(s, t) {
            utree.unite(s, t);
            g -= 1;
        }
    }
    let mut heaps = vec![BinaryHeap::new();n];
    for i in 0..n {
        heaps[utree.find(i)].push(Rev(a[i]));
    }
    let mut rest = BinaryHeap::new();
    let mut ret = 0;
    for i in 0..n {
        if utree.find(i) == i {
            ret += heaps[i].pop().unwrap().0;
            while !heaps[i].is_empty() {
                rest.push(heaps[i].pop().unwrap());
            }
        }
    }
    if g == 1 {
        println!("{}", 0);
        return;
    }

    let mut need = (g - 1) * 2 - g;
    while need > 0 {
        if rest.is_empty() {
            println!("Impossible");
            return;
        }
        ret += rest.pop().unwrap().0;
        need -= 1;
    }
    println!("{}", ret);
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Rev<T>(pub T);

impl<T: PartialOrd> PartialOrd for Rev<T> {
    fn partial_cmp(&self, other: &Rev<T>) -> Option<std::cmp::Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl<T: Ord> Ord for Rev<T> {
    fn cmp(&self, other: &Rev<T>) -> std::cmp::Ordering {
        other.0.cmp(&self.0)
    }
}

#[allow(dead_code)]
pub struct Utree {
    n: usize,
    par: Vec<usize>,
    rank: Vec<usize>,
    size: Vec<usize>,
}


#[allow(dead_code)]
impl Utree {
    pub fn new(n: usize) -> Utree {
        Utree {
            n: n,
            par: (0..n).collect(),
            rank: vec![0; n],
            size: vec![1; n],
        }
    }

    fn find(&mut self, x: usize) -> usize {
        if self.par[x] == x {
            x
        } else {
            let parent = { self.par[x] };
            let ret = self.find(parent);
            self.par[x] = ret;
            ret
        }
    }

    pub fn unite(&mut self, mut x: usize, mut y: usize) {
        x = self.find(x);
        y = self.find(y);
        if x == y {
            return;
        };

        if self.rank[x] < self.rank[y] {
            self.par[x] = y;
            self.size[y] += self.size[x];
        } else {
            self.par[y] = x;
            self.size[x] += self.size[y];
            if self.rank[x] == self.rank[y] {
                self.rank[x] += 1;
            }
        }
    }

    pub fn is_same(&mut self, mut x: usize, mut y: usize) -> bool {
        x = self.find(x);
        y = self.find(y);
        x == y
    }

    fn get_size(&mut self, mut x: usize) -> usize {
        x = self.find(x);
        self.size[x]
    }

    fn size(&mut self) -> usize {
        let mut hset = std::collections::HashSet::new();
        for i in 0..self.n {hset.insert(self.find(i));}
        hset.len()
    }
}


// region template
#[allow(dead_code)]
fn iu(i: i64) -> usize { i as usize }

#[allow(dead_code)]
fn ui(i: usize) -> i64 { i as i64 }

#[allow(dead_code, deprecated)]
fn join<T: std::fmt::Display>(slice: &[T], sep: &str) -> String {
    let strings = slice.iter().map(|t| format!("{}", t)).collect::<Vec<_>>();
    strings.connect(sep)
}

#[allow(dead_code)]
fn arr<'a, S, T>(n: usize, mut f: S) -> Vec<T> where S: FnMut(usize) -> T + 'a {
    (0..n).map(|i| f(i)).collect::<Vec<T>>()
}

#[allow(dead_code)]
fn alt<S, T>(v: Vec<S>) -> T where T: FromIterator<S> {
    v.into_iter().collect::<T>()
}

#[allow(dead_code)]
fn dup<S, T>(v: &[S]) -> T where T: FromIterator<S>, S: Clone {
    v.iter().cloned().collect::<T>()
}

struct Scanner<'a> {
    cin: StdinLock<'a>,
}

#[allow(dead_code)]
impl<'a> Scanner<'a> {
    fn new(cin: StdinLock<'a>) -> Scanner<'a> {
        Scanner { cin: cin }
    }

    fn read1<T: FromStr>(&mut self) -> Option<T> {
        let token = self.cin.by_ref().bytes().map(|c| c.unwrap() as char)
            .skip_while(|c| c.is_whitespace())
            .take_while(|c| !c.is_whitespace())
            .collect::<String>();
        token.parse::<T>().ok()
    }

    fn read<T: FromStr>(&mut self) -> T {
        self.read1().unwrap()
    }

    fn readn<T: FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read::<T>()).collect()
    }

    fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}
// endregion