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: Wrong Answer)

// use std::ops::{Index, IndexMut};
// use std::cmp::{Ordering, min, max};
// use std::collections::{BinaryHeap, BTreeMap};
// use std::collections::btree_map::Entry::{Occupied, Vacant};
// use std::clone::Clone;

fn getline() -> String{
    let mut res = String::new();
    std::io::stdin().read_line(&mut res).ok();
    res
}

macro_rules! readl {
    ($t: ty) => {
        {
            let s = getline();
            s.trim().parse::<$t>().unwrap()
        }
    };
    ($( $t: ty),+ ) => {
        {
            let s = getline();
            let mut iter = s.trim().split(' ');
            ($(iter.next().unwrap().parse::<$t>().unwrap(),)*) 
        }
    };
}

macro_rules! readlvec {
    ($t: ty) => {
        {
            let s = getline();
            let iter = s.trim().split(' ');
            iter.map(|x| x.parse().unwrap()).collect::<Vec<$t>>()
        }
    }
}

macro_rules! debug {
    ($x: expr) => {
        println!("{}: {:?}", stringify!($x), $x)
    }
}

fn printiter<'a, T>(v: &'a T)
where
    &'a T: std::iter::IntoIterator, 
    <&'a T as std::iter::IntoIterator>::Item: std::fmt::Display {
    for (i,e) in v.into_iter().enumerate() {
        if i != 0 {
            print!(" ");
        }
        print!("{}", e);
    }
    println!("");
}

struct ContestPrinter {
    s: String,
}

impl ContestPrinter {
    fn new() -> ContestPrinter {
        ContestPrinter {
            s: String::new(),
        }
    }

    fn print<T>(&mut self, x: T)
        where T: std::fmt::Display {
        self.s.push_str(format!("{}", x).as_str());
    }

    fn println<T>(&mut self, x: T)
        where T: std::fmt::Display {
        self.s.push_str(format!("{}\n", x).as_str());
    }
}

impl std::ops::Drop for ContestPrinter {
    fn drop(&mut self) {
        print!("{}", self.s);
    }
}

struct UnionFind {
    par: Vec<usize>,
    rank: Vec<usize>,
}

impl UnionFind {
    fn new(n: usize) -> UnionFind {
        let mut vec = vec![0;n];
        for i in 0..n {
            vec[i] = i;
        }
        UnionFind {
            par : vec,
            rank : vec![0;n],
        }
    }

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

    fn same(&mut self, a: usize, b: usize) -> bool {
        self.find(a) == self.find(b)
    }

    fn unite(&mut self, a: usize, b: usize){
        let apar = self.find(a);
        let bpar = self.find(b);
        if self.rank[apar] > self.rank[bpar] {
            self.par[bpar] = apar;
        }else{
            self.par[apar] = bpar;
            if self.rank[apar] == self.rank[bpar] {
                self.rank[bpar] += 1;
            }
        }
    }
}

use std::collections::*;
use std::cmp::*;

// #[derive(Clone, Debug)]
struct Heap<T: Ord>(BinaryHeap<T>);

impl<T: Ord> Heap<T> {
    fn new() -> Heap<T> {
        Heap(BinaryHeap::new())
    }
}

impl<T: Ord> std::ops::Deref for Heap<T> {
    type Target = BinaryHeap<T>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T: Ord> std::ops::DerefMut for Heap<T> {
    fn deref_mut(&mut self) -> &mut BinaryHeap<T> {
        &mut self.0
    }
}

impl<T: Ord> PartialEq for Heap<T> {
   fn eq(&self, other: &Heap<T>) -> bool {
       self.peek().unwrap() == other.peek().unwrap()
   }
}

impl<T: Ord> Eq for Heap<T> {}

impl<T: Ord> PartialOrd for Heap<T> {
    fn partial_cmp(&self, other: &Heap<T>) -> Option<Ordering> {
        Some(self.peek().unwrap().cmp(other.peek().unwrap()))
    }
}

impl<T: Ord> Ord for Heap<T> {
    fn cmp(&self, other: &Heap<T>) -> Ordering  {
        self.peek().unwrap().cmp(self.peek().unwrap())
    }
}

fn merge<T: Ord>(x: Heap<T>, y: Heap<T>) -> Heap<T> {
    let (mut x, mut y) = if x.len() < y.len() {
        (y, x)
    } else {
        (x, y)
    };
    while let Some(t) = y.pop() {
        x.push(t);
    }
    x
}

fn main() {
    let mut printer = ContestPrinter::new();
    let (n, m) = readl!(usize, usize);
    let a = readlvec!(i64);
    let a: Vec<_> = a.into_iter().map(|x| -x).collect();
    let mut uf = UnionFind::new(n);
    for _ in 0..m {
        let (x, y) = readl!(usize, usize);
        uf.unite(x, y);
    }
    let mut mp = HashMap::new();
    for i in 0..n {
        let h = mp.entry(uf.find(i)).or_insert(Heap::new());
        h.push(a[i]);
    }
    let mut hh = Heap::new();
    let cn = mp.len();
    for (_, e) in mp {
        hh.push(e);
    }
    let mut ans = 0;
    for _ in 0..cn-1 {
        if let Some(mut x) = hh.pop() {
            if let Some(mut y) = hh.pop() {
                ans += -x.pop().unwrap();
                ans += -y.pop().unwrap();
                if !x.is_empty() || !y.is_empty() {
                    hh.push(merge(x, y));
                }
            } else {
                ans = -1;
                break;
            }
        } else {
            ans = -1;
            break;
        }
    }
    if ans == -1 {
        printer.println("Impossible");
    } else {
        printer.println(ans);
    }
}