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: Accepted)

using System;
using System.Linq;//リストの使用
using System.Collections.Generic;
using System.Text;//テキストの高速出力に必要
class Program
{
static string[] input = Console.ReadLine().Split(' ');
static int n = int.Parse(input[0]);
static int m = int.Parse(input[1]);
static int[] unionfind = new int[n];//親

	static void Main()
	{
		long[] nums = Array.ConvertAll(Console.ReadLine().Split(' '),long.Parse);
    long[][] vertexes = new long[n][];//コストと番号
    int lowVertex = 0;
    int nextVertex = 1;
    int lowNum = -1;
    bool[] usedVertexes = new bool[n];
    long answer = 0;
    int[] minVertexNum = new int[n];
    long[] minVertexCost = new long[n];
    
    for(int i = 0; i < n; i++)
    {
      vertexes[i] = new long[2];
      vertexes[i][0] = nums[i];
      vertexes[i][1] = i;
      minVertexNum[i] = -1;
      minVertexCost[i] = long.MaxValue;
    }
    Array.Sort(vertexes, (a, b) => a[0].CompareTo(b[0]));

    for(int i = 0; i < n; i++)
    {
      unionfind[i] = -1;
    }
    
    for(long i = 0; i < m; i++)
    {
      int[] numsa = Array.ConvertAll(Console.ReadLine().Split(' '),int.Parse);
      UnionFindUnite(numsa[0],numsa[1]);
    }

    int unionCount = UnionFindSizes().Length;
    //Console.WriteLine(unionCount+"az");
    if(unionCount*2-2 > n)
    {
      Console.WriteLine("Impossible");
    }else
    {
      for(int i = 0; i < n; i++)
      {
        if(minVertexCost[UnionFindFind(i)] > nums[i])
        {
          minVertexNum[UnionFindFind(i)] = i;
          minVertexCost[UnionFindFind(i)] = nums[i];
        }
      }

      for(int i = 0; i < n; i++)
      {
        if(minVertexNum[i] != -1)
        {
          usedVertexes[minVertexNum[i]] = true;
          answer += minVertexCost[i];
        }
      }

      for(int i = 0; i < unionCount-2; i++)
      {
        while(true)
        {
          lowNum++;
          
          if(!usedVertexes[vertexes[lowNum][1]])
          {
            answer += vertexes[lowNum][0];
            break;
          }
        }
      }

      if(unionCount == 1) answer = 0;
      Console.WriteLine(answer);
    }
	}

  static void UnionFindUnite(int x, int y)
  {//unionfindで頂点x,yをO(log頂点数)で結合
    x = UnionFindFind(x);
    y = UnionFindFind(y);
    if(x == y) return;

    if(unionfind[x] > unionfind[y])
    {
      int swapMemo = unionfind[x];
      unionfind[x] = unionfind[y];
      unionfind[y] = swapMemo;
    }
    unionfind[x] += unionfind[y];
    unionfind[y] = x;
  }

  static int UnionFindFind(int x)
  {//unionfindで頂点xが属する集合をO(log頂点数)で返す
    if(unionfind[x] < 0) return x;
    return (unionfind[x] = UnionFindFind(unionfind[x]));
  }

  static int UnionFindSize(int x)
  {//unionfindで頂点xが属する集合の大きさをO(log頂点数)で返す
    return (-unionfind[UnionFindFind(x)]);
  }

  static int[] UnionFindSizes()
  {//unionfindで各集合の大きさをO(頂点数 *log頂点数)で返す
  //例えば{1,2,5,2}なら{1,2,1}(順不同)を返す
    int[] answers;
    int answerCount = 1;
    int answerCountSub = 0;
    int n = unionfind.Length;
    int[] parents = new int[n];
    for(int i = 0; i < n; i++)
    {
      parents[i] = UnionFindFind(i);
    }
    Array.Sort(parents);

    for(int i = 1; i < n; i++)
    {
      if(parents[i-1] != parents[i]) answerCount++;
    }
    answers = new int[answerCount];
    answers[0]++;

    for(int i = 1; i < n; i++)
    {
      if(parents[i-1] != parents[i])
      {
        answerCountSub++;
      }
      answers[answerCountSub]++;
    }
    
    return answers;
  }
  
}