#include <bits/stdc++.h>
using namespace std;
struct Point {
  int x;
  int y;
  int z;
  int id;
};
bool compY(Point a, Point b) {
  if (a.y != b.y) {
    return a.y < b.y;
  }
  return a.z < b.z;
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
  int n;
  cin >> n;
  map<int, vector<Point>> m;
  for (int i = 0; i < n; i++) {
    int x, y, z;
    cin >> x >> y >> z;
    m[x].push_back({x, y, z, i});
  }
  vector<pair<int, int>> ans;
  vector<bool> deleted(n, false);
  for (auto &e : m) {
    if (e.second.size() < 2) {
      continue;
    }
    vector<Point> a = e.second;
    int k = a.size();
    if (k < 2) {
      continue;
    }
    sort(a.begin(), a.end(), compY);
    for (int i = 0; i < k - 1; i++) {
      if (a[i].y == a[i + 1].y) {
        ans.emplace_back(a[i].id, a[i + 1].id);
        deleted[a[i].id] = true;
        deleted[a[i + 1].id] = true;
        i++;
      }
    }
    int l = 0;
    int r = 0;
    while (l < k) {
      if (deleted[a[l].id]) {
        l++;
        continue;
      }
      r = max(r, l + 1);
      while (r < k && deleted[a[r].id]) {
        r++;
      }
      if (r == k) {
        break;
      }
      ans.emplace_back(a[l].id, a[r].id);
      deleted[a[l].id] = true;
      deleted[a[r].id] = true;
      l++;
    }
  }
  bool havePrev = false;
  Point prev;
  for (auto &e : m) {
    bool here = false;
    Point cur;
    for (auto &x : e.second) {
      if (!deleted[x.id]) {
        here = true;
        cur = x;
        break;
      }
    }
    if (!here) {
      continue;
    }
    if (havePrev) {
      ans.emplace_back(prev.id, cur.id);
      havePrev = false;
    } else {
      havePrev = true;
      prev = cur;
    }
  }
  for (auto &e : ans) {
    cout << e.first + 1 << ' ' << e.second + 1 << '\n';
  }
}
