/*
  Copyright 2013 Marek "p2004a" Rusinowski
  Computing MST - Borůvka's algorithm
*/
#include <cstdio>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

template <class T, class Compare = less<T> >
class LeftistHeap {
 public:
  class LeftistHeapNode {
   public:
    T value;
    LeftistHeapNode *left, *right;
    int s;

    LeftistHeapNode(T vvalue, LeftistHeapNode *lleft, LeftistHeapNode *rright, int ss)
     : value(vvalue), left(lleft), right(rright), s(ss) {}

    LeftistHeapNode(const LeftistHeapNode &node) : value(node.value), left(NULL), right(NULL), s(node.s) {
      if (node.left != NULL) left = new LeftistHeapNode(*node.left);
      if (node.right != NULL) right = new LeftistHeapNode(*node.right);
    }

    ~LeftistHeapNode() {
      delete left;
      delete right;
    }
  };

  LeftistHeapNode *merge(LeftistHeapNode *h1, LeftistHeapNode *h2) {
    if (h1 == NULL) return h2;
    if (h2 == NULL) return h1;
    if (!cmp(h1->value, h2->value)) swap(h1, h2);
    if (h1->left == NULL) h1->left = h2;
    else {
      h1->right = merge(h1->right, h2);
      if (h1->left->s < h1->right->s) swap(h1->left, h1->right);
      h1->s = h1->right->s + 1;
    }
    return h1;
  }

 private:
  LeftistHeapNode *root;
  size_t heap_size;
  Compare cmp;

 public:
  LeftistHeap() : root(NULL), heap_size(0) {}

  LeftistHeap(const LeftistHeap &heap) : root(NULL), heap_size(heap.heap_size) {
    if (heap.root != NULL) root = new LeftistHeapNode(*heap.root);
  }

  ~LeftistHeap() {
    delete root;
  }

  LeftistHeap &operator=(const LeftistHeap &heap) {
    delete root;
    root = new LeftistHeapNode(*heap.root);
    heap_size = heap.heap_size;
    return *this;
  }

  LeftistHeapNode *insert(T value) {
    LeftistHeapNode *node = new LeftistHeapNode(value, NULL, NULL, 0);
    root = merge(root, node);
    ++heap_size;
    return node;
  }

  T top() {
    if (root == NULL) throw "Cannot get min from empty heap";
    return root->value;
  }

  T deltop() {
    if (root == NULL) throw "Cannot del min from empty heap";
    LeftistHeapNode *tmp = root;
    root = merge(root->left, root->right);
    --heap_size;
    tmp->left = tmp->right = NULL;
    T value = tmp->value;
    delete tmp;
    return value;
  }

  void merge(LeftistHeap &heap) {
    root = merge(root, heap.root);
    heap_size += heap.heap_size;
    heap.root = NULL;
    heap.heap_size = 0;
  }

  size_t size() {
    return heap_size;
  }
};

class FindUnion {
  int *root, *rank;
  
 public:
  FindUnion(int n) {
    root = new int [n];
    rank = new int [n];
    for (int i = 0; i < n; ++i) root[i] = i;
  }
  
  ~FindUnion() {
    delete root;
    delete rank;
  }
 
  int find_set(int v) {
    if (root[v] == v) return v;
    root[v] = find_set(root[v]);
    return root[v];
  }
   
  void union_sets(int v, int u) {
    v = find_set(v);
    u = find_set(u);
    if (rank[v] < rank[u]) {
      root[v] = u;
    } else if (rank[v] > rank[u]) {
      root[u] = v;
    } else {
      root[v] = u;
      ++rank[v];
    }
  }
};

int main() {
  int n, m;
  scanf("%d %d", &n, &m);
  vector<LeftistHeap<pair<int, pair<int, int> > > > edges(n);
  FindUnion fu(n);
  for (int i = 0; i < m; ++i) {
    int a, b, c;
    scanf("%d %d %d", &a, &b, &c);
    --a, --b;
    edges[a].insert(make_pair(c, make_pair(a, b)));
    edges[b].insert(make_pair(c, make_pair(b, a)));
  }
  
  vector<pair<int, int> > out;
  for (int i = 1; i < n; ++i) {
    int u, v = fu.find_set(i);
    while ((u = fu.find_set(edges[v].top().second.second)) == v) {
      edges[v].deltop();
    }
    out.push_back(edges[v].top().second);
    fu.union_sets(u, v);
    if (v != fu.find_set(v)) swap(u, v);
    edges[v].merge(edges[u]);
  }
  
  for (vector<pair<int, int> >::iterator it = out.begin(); it != out.end(); ++it) {
    printf("%d %d\n", it->first + 1, it->second + 1);
  }
  return 0;
}
