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++14 (GCC 5.4.1) (judge verdict: Runtime Error)

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cfloat>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>

// c++11
#include <array>
#include <tuple>
#include <unordered_map>
#include <unordered_set>

#define mp make_pair
#define mt make_tuple
#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;

const int INF = 1 << 29;
const ll LL_INF = 1LL << 60;
const double EPS = 1e-9;
const ll MOD = 1000000007;

const int dx[] = {1, 0, -1, 0}, dy[] = {0, -1, 0, 1};
// UnionFind
class UnionFind
{
public:
  UnionFind(int size_) : parent(size_, -1), __size(size_) {}
  void unite(int x, int y)
  {
    if ((x = find(x)) != (y = find(y)))
    {
      if (parent[y] < parent[x])
        std::swap(x, y);
      parent[x] += parent[y];
      parent[y] = x;
      __size--;
    }
  }
  bool is_parent(int x) { return find(x) == x; }
  bool is_same(int x, int y) { return find(x) == find(y); }
  int find(int x) { return parent[x] < 0 ? x : parent[x] = find(parent[x]); }
  int size(int x) { return -parent[find(x)]; }
  int size() const { return __size; }

private:
  std::vector<int> parent;
  int __size;
};
// UnionFind

int N, M;
vector<int> A;
using P = priority_queue<pii, vector<pii>, greater<pii>>;

ll result;
int main()
{
  cin >> N >> M;
  A.resize(N);
  for (auto &val : A)
  {
    cin >> val;
  }
  UnionFind ut(N);
  map<int, P> nodes;
  for (int i = 0; i < M; i++)
  {
    int x, y;
    cin >> x >> y;
    ut.unite(x, y);
  }
  for (int i = 0; i < N; i++)
  {
    int p = ut.find(i);
    nodes[p].emplace(mp(A[i], i));
  }
  // check
  int forest = 0;
  int rest = 0;
  for (int i = 0; i < N; i++)
  {
    if (nodes[i].size() > 0)
    {
      forest++;
      rest += nodes[i].size() - 1;
    }
  }
  int need = forest - 1;
  if (need <= 0)
  {
    cout << 0 << endl;
    return 0;
  }

  if (need > rest)
  {
    
    cout << "Impossible" << endl;
    return 0;
  }
  assert(false);
  vector<int> ones;
  for (int i = 0; i < N; i++)
  {
    if (nodes[i].size() == 1)
    {
      auto &p = nodes[i].top();
      ones.emplace_back(p.second);
      result += p.second;
      nodes.erase(i);
    }
    else if (nodes[i].size() == 0)
    {
      nodes.erase(i);
    }
  }

  // while (nodes.size() > 1)
  // {
  //   int p, q;
  //   p = q = -1;
  //   for (auto &val : nodes)
  //   {
  //     if (p == -1)
  //     {
  //       p = val.first;
  //     }
  //     else if (q == -1)
  //     {
  //       q = val.first;
  //     }
  //     else
  //     {
  //       break;
  //     }
  //   }
  //   if (p == -1 || q == -1)
  //   {
  //     break;
  //   }

  //   auto &p_nodes = nodes[p];
  //   auto &q_nodes = nodes[q];
  //   int p_val = p_nodes.top().first;
  //   p_nodes.pop();
  //   result += p_val;
  //   int q_val = q_nodes.top().first;
  //   q_nodes.pop();
  //   result += q_val;

  //   if (p_nodes.size() < q_nodes.size())
  //   {
  //     swap(p, q);
  //     swap(p_nodes, q_nodes);
  //   }
  //   //merge
  //   while (!q_nodes.empty())
  //   {
  //     p_nodes.emplace(q_nodes.top());
  //     q_nodes.pop();
  //   }
  //   nodes.erase(q);
  // }
  // int root_idx = -1;
  // for (int i = 0; i < N; i++)
  // {
  //   if (nodes[i].size() > 0)
  //   {
  //     root_idx = i;
  //     break;
  //   }
  // }
  // P root = nodes[root_idx];
  
  // for (int i = 0; i < ones.size(); i++)
  // {
  //   int cost = root.top().first;
  //   root.pop();
  //   result += cost;
  // }
  cout << result << endl;
  return 0;
}