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: Wrong Answer)

#include <bits/stdc++.h>
using namespace std;

using i64=int64_t;

#define rep(i,x,y) for(i64 i=i64(x),i##_max_for_repmacro=i64(y); i<i##_max_for_repmacro; ++i)
#define debug(x) #x << "=" << (x)
 
#ifdef DEBUG
#define _GLIBCXX_DEBUG
#define print(x) std::cerr << debug(x) << " (L:" << __LINE__ << ")" << std::endl
#else
#define print(x)
#endif
 
const int inf=1.01e9;
const i64 inf64=4.01e18;
const double eps=1e-9;
 
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec){
    os << "[";
    for (const auto &v : vec) {
        os << v << ",";
    }
    os << "]";
    return os;
}

class quick_find_weighted{
	public:
	int size=0,count_group;
	vector<int> belong;
	vector<set<int>> groups;
	quick_find_weighted(int size_):size(size_),belong(size_),groups(size_){
        count_group=size;
		for(int i=0; i<size; ++i){
			belong[i]=i;
			groups[i].insert(i);
		}
	}
	void unite(int x,int y){
		int gx=belong[x],gy=belong[y];
        assert(gx!=-1);
        assert(gy!=-1);
		if(gx==gy) return;
		if(groups[gx].size()<groups[gy].size()) swap(gx,gy);
		for(int z:groups[gy]) belong[z]=gx;
		groups[gx].insert(groups[gy].begin(),groups[gy].end());
		groups[gy].clear();
        --count_group;
	}
	int find(int x)const{
		return belong[x];
	}
    bool is_same_group(int x,int y)const{
        return find(x)==find(y);   
    }
	void erase(int x){
		int gx=belong[x];
		if(gx==-1) return;
		belong[x]=-1;
		groups[gx].erase(x);
	}
    int group_size(int x)const{
        int gx=belong[x];
        assert(gx!=-1);
        return groups[gx].size();   
    }
};


void solve(){
    int N,M;
    cin >> N >> M;
    
    vector<i64> a(N);
    rep(i,0,N) cin >> a[i];

    quick_find_weighted uf(N);
    rep(i,0,M){
        int x,y;
        cin >> x >> y;
        uf.unite(x,y);
    }

    if(uf.count_group==1){
        cout << 0 << endl;
        return;
    }

    priority_queue<pair<i64,int>,vector<pair<i64,int>>,greater<pair<i64,int>>> que;
    vector<priority_queue<pair<i64,int>,vector<pair<i64,int>>,greater<pair<i64,int>>>> cost(N);
    i64 ans=0;
    int cnt=0;
    rep(i,0,N){
        int p=uf.belong[i];
        if(p!=i) continue;
        if(uf.groups[p].size()==1){
            for(int j:uf.groups[p]) ans+=a[j];
            ++cnt;
            continue;
        }
            
        i64 mi=inf64;
        int idx;
        for(int j:uf.groups[p]){
            cost[p].push(make_pair(a[j],j));
            if(a[j]<mi){
                mi=a[j];
                idx=j;
            }
        }
        que.push(make_pair(mi,idx));
    }

    while(que.size()>1){
        print(que.size());
        int x=que.top().second;
        que.pop();
        int y=que.top().second;
        que.pop();

        ans+=a[x]+a[y];
        print(x);
        print(y);

        int p=uf.find(x),q=uf.find(y);
        cost[p].pop();
        cost[q].pop();
        uf.unite(p,q);
        if(uf.find(p)==p){
            while(cost[q].size()>0){
                print(cost[q].size());
                auto tmp=cost[q].top();
                cost[q].pop();
                cost[p].push(tmp);
            }
        }else{
            while(cost[p].size()>0){
                auto tmp=cost[p].top();
                cost[p].pop();
                cost[q].push(tmp);
            }
        }
        int r=uf.find(p);
        if(cost[r].size()>1) que.push(cost[r].top());
        else if(cost[r].size()==1){
            ans+=cost[r].top().first;
            ++cnt;
        }else if(uf.count_group>1){
            cout << "Impossible" << endl;
            return;
        }
    }

    int p=que.size()?que.top().second:0;
    if(uf.count_group>1 and cost[p].size()<cnt){
        cout << "Impossible" << endl;
        return;
    }
    rep(i,0,cnt){
        int x=cost[p].top().second;
        cost[p].pop();
        ans+=a[x];
    }

    cout << ans << endl;
}

int main(){
    std::cin.tie(0);
    std::ios::sync_with_stdio(false);
    cout.setf(ios::fixed);
    cout.precision(16);
    solve();
    return 0;
}