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.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;
    bool[] usedVertexes = new bool[n];
    long answer = 0;
    
    for(int i = 0; i < n; i++)
    {
      vertexes[i] = new long[2];
      vertexes[i][0] = nums[i];
      vertexes[i][1] = i;
    }
    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]);

      /*
      for(int j = 0; j < n; j++)
      {
        Console.WriteLine(i+" "+j+" p "+whatParent(j));
      }
      */
    }

    /*
    for(int j = 0; j < n; j++)
    {
      Console.WriteLine(j+" p "+whatParent(j));
    }
    */
    
    while(true)
    {
      if(nextVertex >= n) break;
      
      int aa = lowVertex;
      int bb = nextVertex;

      if(UnionFindFind((int)vertexes[aa][1]) != UnionFindFind((int)vertexes[bb][1]))
      {
        //Console.WriteLine(parents[vertexes[aa][1]] +" "+ whatParent(vertexes[bb][1]));
        UnionFindUnite((int)vertexes[aa][1],(int)vertexes[bb][1]);
        usedVertexes[aa] = true;
        usedVertexes[bb] = true;
        answer += vertexes[aa][0] + vertexes[bb][0];
        Console.WriteLine(aa+" "+bb+" "+vertexes[aa][1] +" "+ vertexes[bb][1]
          +" "+vertexes[aa][0] +" "+ vertexes[bb][0]);

        while(true)
        {
          if(lowVertex == n) break;
        
          if(usedVertexes[lowVertex]) lowVertex++;
          else break;
        }

        nextVertex++;
        if(nextVertex == lowVertex) nextVertex++;
        if(nextVertex >= n) break;
      }else
      {
        nextVertex++;
        if(nextVertex >= n) break;
      }
    }

    for(int i = 1; i < n; i++)
    {
      //Console.WriteLine(i+" "+whatParent(0)+" "+whatParent(i));
      if(UnionFindFind(0) != UnionFindFind(i))
      {
        answer = -1;
      }
    }

		Console.WriteLine((answer == -1)?"Impossible":answer.ToString());
	}

  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)]);
  }
  
}