#include "bits/stdc++.h"

#define clr(x) memset((x), 0, sizeof(x))
#define all(x) (x).begin(), (x).end()
#define pb push_back
#define mp make_pair
#define in(x) int (x); input((x));
#define x first
#define y second
typedef int itn;

#define next next12345
#define prev prev12345
#define left lefdsf232
#define right rig43783
#define x1 x12345
#define y1 y12345

using namespace std;

template<typename T>
T gcd(T x, T y) {
    while (y > 0) {
        x %= y;
        swap(x, y);
    }
    return x;
}

template<class _T>
inline _T sqr(const _T &x) {
    return x * x;
}

template<class _T>
inline string tostr(const _T &a) {
    ostringstream os("");
    os << a;
    return os.str();
}

typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
const long double PI = 3.1415926535897932384626433832795L;

template<typename T>
inline void input(T &a) {
    static int c;
    a = 0;
    while (!isdigit(c = getchar()) && c != '-') {}
    char neg = 0;
    if (c == '-') {
        neg = 1;
        c = getchar();
    }
    while (isdigit(c)) {
        a = 10 * a + c - '0';
        c = getchar();
    }
    if (neg) a = -a;
}

template<typename T = int>
inline T nxt() {
    T res;
    input(res);
    return res;
}

const int N = 30000;

struct dsu {
    int p[N];
    int sz[N];
    int cnt;

    void init(int n) {
        for (int i = 0; i < n; ++i) {
            p[i] = i;
            sz[i] = 1;
        }
        cnt = n;
    }

    inline int get(int v) {
        if (p[v] != v) {
            p[v] = get(p[v]);
        }
        return p[v];
    }

    inline void unite(int a, int b) {
        a = get(a);
        b = get(b);
        if (a == b) {
            return;
        }
        --cnt;
        if (sz[a] > sz[b]) {
            swap(a, b);
        }
        p[a] = b;
        sz[b] += sz[a];
    }
};

const int K = 17;

vector <dsu> x[K];

struct edge {
    int from;
    int to;
    int len;
    int id;
    bool operator<(const edge & e) const {
        return len < e.len;
    }
};

int k;


edge e[N];

dsu empty;

dsu W;

int vertices[N + N + N + N];

int check(int l, int r) {
    int p1 = (l + k - 1) / k;
    int p2 = (r + 1) / k;

    int X = p1 * k;
    int Y = p2 * k;

    p2 -= p1 + 1;

    int sz = 0;

    if (p2 < 0) {
        for (int x = l; x <= r; ++x) {
            int A = e[x].from;
            int B = e[x].to;
            if (A != B) {
                vertices[sz++] = A;
                vertices[sz++] = B;
            }
        }

        W.cnt = empty.cnt;
        for (int i = 0; i < sz; ++i) {
            W.p[vertices[i]] = vertices[i];
            W.sz[vertices[i]] = 1;
        }

        for (int x = l; x <= r; ++x) {
            int A = e[x].from;
            int B = e[x].to;
            if (A != B) W.unite(A, B);
        }
    } else {
        dsu & v = x[p1][p2];

        for (int x = l; x < X; ++x) {
            int A = v.get(e[x].from);
            int B = v.get(e[x].to);
            if (A != B) {
                vertices[sz++] = A;
                vertices[sz++] = B;
            }
        }

        for (int x = Y; x <= r; ++x) {
            int A = v.get(e[x].from);
            int B = v.get(e[x].to);
            if (A != B) {
                vertices[sz++] = A;
                vertices[sz++] = B;
            }
        }

        W.cnt = v.cnt;
        for (int i = 0; i < sz; ++i) {
            W.p[vertices[i]] = vertices[i];
            W.sz[vertices[i]] = 1;
        }

        for (int i = 0; i < sz; i += 2) {
            W.unite(vertices[i], vertices[i + 1]);
        }
    }

    return W.cnt == 1;
}

int main() {
    //#define int long
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#else
#define fname "onearmedbandit"
    //freopen(fname".in", "r", stdin);
    //freopen(fname".out", "w", stdout);
#endif

    int n = nxt(), m = nxt();

    for (int i = 0; i < m; ++i) {
        e[i].from = nxt() - 1;
        e[i].to = nxt() - 1;
        e[i].len = nxt();
        e[i].id = i;
    }


    empty.init(n);

    sort(e, e + m);

    k = (m + K - 1) / K;



    for (int i = 0, t = 0; i < m; i += k, ++t) {
        for (int j = i; j < m; ++j) {
            if (j % k == 0) {
                if (j == i) {
                    x[t].push_back(dsu());
                    x[t].back().init(n);
                } else {
                    x[t].push_back(dsu());
                    dsu & last = x[t][x[t].size() - 2];
                    dsu & cur = x[t].back();

                    memcpy(cur.p, last.p, sizeof(int) * n);
                    memcpy(cur.sz, last.sz, sizeof(int) * n);
                    cur.cnt = last.cnt;
                }
            }
            x[t].back().unite(e[j].from, e[j].to);
        }
    }


    //cout << check(0, m - 1) << endl;

    //return 0;


    int r = 0;

    int best = INT_MAX;

    int L = 0, R = m - 1;

    for (int i = 0; i < m; ++i) {
        r = max(r, i + n - 2);
        while (r < m && !check(i, r)) {
            ++r;
        }
        if (r < m) {
            int v = e[r].len - e[i].len;
            if (v < best) {
                best = v;
                L = i, R = r;
            }
        } else {
            break;
        }
    }

    vector <int> ans;

    empty.init(n);

    for (int x = L; x <= R; ++x) {
        int A = empty.get(e[x].from);
        int B = empty.get(e[x].to);
        if (A != B) {
            ans.push_back(e[x].id);
            empty.unite(A, B);
        }
    }

//    long long mem = 0;
//    for (int i = 0; i < K; ++i) {
//        for (const auto & X : x[i]) {
//            mem += sizeof(X);
//        }
//    }
//
//    cerr << mem << endl;

    //cout << ans.size() << endl;
    assert(ans.size() == n - 1);

    sort(all(ans));

    for (int x : ans) {
        cout << x + 1 << " ";
    }

    cout << "\n";

#ifdef LOCAL
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
    return 0;
}