Language: C++

#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <map>
#include <tuple>
#include <vector>
using namespace std;

#define MAX 100005
#define COST_MAX 1000000005

#define rep(i, n) for (int i = 0; i < int(n); i++)

// 素集合データ構造
struct UnionFind {
    // par[i]：データiが属する木の親の番号。i ==
    // par[i]のとき、データiは木の根ノードである
    vector< int > par;
    // sizes[i]：根ノードiの木に含まれるデータの数。iが根ノードでない場合は無意味な値となる
    vector< int > sizes;

    UnionFind(int n) : par(n), sizes(n, 1) {
        // 最初は全てのデータiがグループiに存在するものとして初期化
        rep(i, n) par[i] = i;
    }

    // データxが属する木の根を得る
    int find(int x) {
        if (x == par[x]) return x;
        return par[x] =
                   find(par[x]);  // 根を張り替えながら再帰的に根ノードを探す
    }

    // 2つのデータx, yが属する木をマージする
    void unite(int x, int y) {
        // データの根ノードを得る
        x = find(x);
        y = find(y);

        // 既に同じ木に属しているならマージしない
        if (x == y) return;

        // xの木がyの木より大きくなるようにする
        if (sizes[x] < sizes[y]) swap(x, y);

        // xがyの親になるように連結する
        par[y] = x;
        sizes[x] += sizes[y];
        // sizes[y] = 0;  // sizes[y]は無意味な値となるので0を入れておいてもよい
    }

    // 2つのデータx, yが属する木が同じならtrueを返す
    bool same(int x, int y) { return find(x) == find(y); }

    // データxが含まれる木の大きさを返す
    int size(int x) { return sizes[find(x)]; }
};

bool root[MAX];

int main() {
    int N, M;

    cin >> N >> M;

    UnionFind uf(N);
    vector< pair< int, int > > cost(N);
    vector< int > root_set;
    vector< int > merged_root;

    for (int i = 0; i < N; i++) {
        cin >> cost[i].first;
        cost[i].second = i;
        root[i] = true;
    }

    for (int i = 0; i < M; i++) {
        int x, y;
        cin >> x >> y;
        uf.unite(x, y);
    }

    if (N == 1) {
        cout << 0 << endl;
        return 0;
    }

    sort(cost.begin(), cost.end());
    for (auto x : cost) {
        group_cost[uf.find(x.second)].push_back(x.first);
    }

    int cnt = 0;

    for (int i = 0; i < N; i++) {
        if (uf.size(i) == 1) {
            cnt--;
            root_set.push_back(i);
        } else if (root[uf.find(i)]) {
            cnt += uf.size(i);
            root[uf.find(i)] = false;
            root_set.push_back(uf.find(i));
        }
    }

    if (cnt < 0) {
        cout << "Impossible" << endl;
        return 0;
    }

    long long int ans = 0;

    merged_root.push_back(root_set[0]);
    while (uf.size(0) != N) {
        int r0 = root_set[0];
        int min = COST_MAX;
        for (int x : merged_root) {
            if (min > group_cost[x][0]) {
                min = group_cost[x][0];
                r0 = x;
            }
        }

        int r1 = root_set[1];
        root_set.erase(root_set.begin() + 1);
        merged_root.push_back(r1);

        ans += group_cost[r0][0];
        ans += group_cost[r1][0];

        group_cost[r0].erase(group_cost[r0].begin());
        group_cost[r1].erase(group_cost[r1].begin());
        uf.unite(r0, r1);
    }

    cout << ans << endl;
}


Compiler output:
a.cc: In function 'int main()':
a.cc:91:9: error: 'group_cost' was not declared in this scope
   91 |         group_cost[uf.find(x.second)].push_back(x.first);
      |         ^~~~~~~~~~
a.cc:119:23: error: 'group_cost' was not declared in this scope
  119 |             if (min > group_cost[x][0]) {
      |                       ^~~~~~~~~~
a.cc:129:16: error: 'group_cost' was not declared in this scope
  129 |         ans += group_cost[r0][0];
      |                ^~~~~~~~~~