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 C# (Mono 4.6.2.0) (judge verdict: Wrong Answer)

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Diagnostics;
using static System.Console;
//using System.Numerics;
//using static System.Math;

class Program
{
    static void Main()
    {
        //SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
        new Program().solve();
        Out.Flush();
    }
    Scanner cin = new Scanner();
    readonly int[] dd = { 0, 1, 0, -1, 0 }; //→↓←↑
    readonly int mod = 1000000007;

    int N, M;
    UnionFind U;
    long[] A;
    long ans;
    void solve()
    {
        N = cin.nextint;
        if (N == 1)
        {
            WriteLine(0);
            return;
        }
        M = cin.nextint;
        U = new UnionFind(N);
        A = cin.scanlong;
        for (int i = 0; i < M; i++)
        {
            U.Unite(cin.nextint, cin.nextint);
        }

        int id = 0;
        var G = new List<List<long>>();
        var ch = new int[N];
        for (int i = 0; i < N; i++)
        {
            ch[i] = -1;
        }

        for (int i = 0; i < N; i++)
        {
            int x = U.FindSet(i);
            if (ch[x] == -1)
            {
                ch[x] = id;
                G.Add(new List<long> { A[i] });
                id++;
            }
            else
            {
                G[ch[x]].Add(A[i]);
            }
        }

        int must = (id - 1) * 2;
        //int yozyo = 0;
        //int cnt = 0;
        for (int i = 0; i < id; i++)
        {
            G[i].Sort();
            //WriteLine(string.Join(" ", G[i]));
            //if (G.Count - 1 < G[i].Count)
            //{
            //    G[i].RemoveRange(G.Count - 1, G[i].Count - G.Count + 1);
            //}

            //WriteLine(string.Join(" ", G[i]));
        }
        G.Sort((a, b) => b.Count - a.Count);

        var Last = new List<long>();

        int nagasa = G[0].Count;

        for (int i = 1; i < id; i++)
        {
            nagasa = nagasa + G[i].Count - 2;
            if(nagasa == 0 && i != id - 1)
            {
                WriteLine("Impossible");
                return;
            }
        }


        for (int i = 0; i < id; i++)
        {
            ans += G[i][0];
            G[i].RemoveAt(0);
            Last.AddRange(G[i]);
        }
        Last.Sort();
        for (int i = id; i < must; i++)
        {
            ans += Last[i - id];
        }
        WriteLine(ans);

        //while (G.Count > 1)
        //{
        //    ans += G[0][0] + G[1][0];
        //    G[0].RemoveAt(0);
        //    G[1].RemoveAt(0);
        //    G[0].AddRange(G[1]);
        //    G.RemoveAt(1);
        //    if (G[0].Count == 0 && G.Count > 1)
        //    {
        //        WriteLine("Impossible");
        //        return;
        //    }
        //    G[0].Sort();
        //    if (G.Count - 1 < G[0].Count)
        //    {
        //        G[0].RemoveRange(G.Count - 1, G[0].Count - G.Count + 1);
        //    }
        //}

        //WriteLine(ans);
    }

}

class UnionFind
{
    internal int[] rank;
    internal int[] p;
    internal int[] weight;
    public UnionFind(int size)
    {
        rank = new int[size];
        p = new int[size];
        weight = new int[size];
        for (int i = 0; i < size; i++)
        {
            rank[i] = 0;
            p[i] = i;
            weight[i] = 1;
        }
    }
    public void Unite(int x, int y)
    {
        x = FindSet(x);
        y = FindSet(y);
        if (x == y) return;
        if (rank[x] > rank[y])
        {
            p[y] = x;
            weight[x] += weight[y];
        }

        if (rank[x] < rank[y])
        {
            p[x] = y;
            weight[y] += weight[x];
        }
        if (rank[x] == rank[y])
        {
            p[x] = y;
            rank[y]++;
            weight[y] += weight[x];
        }
    }
    public bool Same(int x, int y)
    {
        return FindSet(x) == FindSet(y);
    }
    public int FindSet(int x)
    {
        var H = new HashSet<int>();
        while (p[x] != x)
        {
            H.Add(x);
            x = p[x];
        }
        foreach (var h in H)
        {
            p[h] = x;
        }
        return x;
    }
    public int Weight(int x)
    {
        return weight[FindSet(x)];
    }
}

class Scanner
{
    string[] s; int i;
    char[] cs = new char[] { ' ' };
    public Scanner() { s = new string[0]; i = 0; }
    public string[] scan { get { return ReadLine().Split(); } }
    public int[] scanint { get { return Array.ConvertAll(scan, int.Parse); } }
    public long[] scanlong { get { return Array.ConvertAll(scan, long.Parse); } }
    public double[] scandouble { get { return Array.ConvertAll(scan, double.Parse); } }
    public string next
    {
        get
        {
            if (i < s.Length) return s[i++];
            string st = ReadLine();
            while (st == "") st = ReadLine();
            s = st.Split(cs, StringSplitOptions.RemoveEmptyEntries);
            i = 0;
            return next;
        }
    }
    public int nextint { get { return int.Parse(next); } }
    public long nextlong { get { return long.Parse(next); } }
    public double nextdouble { get { return double.Parse(next); } }
}