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 Kotlin (1.0.0) (judge verdict: Accepted)

import java.util.*

fun main(args: Array<String>) {
    val (N, M) = readLine()!!.split(" ").map{it.toInt()}
    val a = readLine()!!.split(" ").map{it.toLong()}
    val uf = UnionFind(N + 1L)

    for (i in 1..M) {
        val (x, y) = readLine()!!.split(" ").map{it.toLong()}
        uf.unite(x, y)
    }

    val qs = Array(N + 1) { PriorityQueue<Long>() }
    for (i in 0L until N) {
        val v = uf.find(i).toInt()
        qs[v].add(a[i.toInt()])
    }

    if (N - 1 == M) {
        println(0)
        return
    }

    var res = 0L
    var cnt = 0
    val Q = PriorityQueue<Long>()

    for (i in 0 until N) {
        if (qs[i].isNotEmpty()) {
            cnt++
            res += qs[i].poll()
            Q.addAll(qs[i])
        }
    }

    while (Q.isNotEmpty() && cnt < (N - M - 1) * 2) {
        res += Q.poll()
        cnt++
    }

    if (cnt == (N - M - 1) * 2) {
        println(res)
    } else {
        println("Impossible")
    }
}

class UnionFind(n: Long) {
    val size = n.toInt()

    private val parent: Array<Long>
    private val cardinality: Array<Long>

    init {
        parent = Array(size) { -1L }
        cardinality = Array(size) { 1L }
    }

    /**
     * Find a root element of a set `x` belongs to.
     */
    fun find(x: Long): Long {
        return if (parent[x.toInt()] == -1L) {
            x
        } else {
            parent[x.toInt()] = find(parent[x.toInt()])
            parent[x.toInt()]
        }
    }

    /**
     * Unite sets contain two elements `x` and `y`.
     * If `x` and `y` already belong to a same set, nothing happens.
     *
     * @return If `x` and `y` belong to a same set, return false.
     */
    fun unite(x: Long, y: Long): Boolean {
        val u = find(x).toInt()
        val v = find(y).toInt()
        if (u == v) {
            return false
        }

        val newSize = cardinality[v] + cardinality[u]

        if (cardinality[u] < cardinality[v]) {
            parent[u] = v.toLong()
            cardinality[v] = newSize
        } else {
            parent[v] = u.toLong()
            cardinality[u] = newSize
        }

        return true
    }

    /**
     * Check whether `x` and `y` belongs to a same set.
     *
     * @return `true` if `x` and `y` are in a same set.
     */
    fun same(x: Long, y: Long): Boolean {
        return find(x) == find(y)
    }

    /**
     * Get a size of a set `x` belongs to.
     */
    fun getCardinalityOf(x: Long): Long {
        return cardinality[find(x).toInt()]
    }
}