#include <bits/stdc++.h>
using namespace std;
struct point {
  int p, x, y, z;
  bool operator<(const point rhs) const {
    if (x != rhs.x) return x < rhs.x;
    if (y != rhs.y) return y < rhs.y;
    return z < rhs.z;
  }
} a[50010];
int n;
void listprint(vector<point> &p) {
  for (int i = 0, j = p.size(); i < j; i += 2)
    printf("%d %d\n", p[i].p, p[i + 1].p);
}
void amel(vector<point> &p, vector<point> &tr) {
  vector<point> q;
  for (int i = 0, nn = p.size(); i < nn;) {
    if (i == nn - 1 || p[i].y != p[i + 1].y) {
      q.push_back(p[i++]);
      continue;
    }
    do {
      printf("%d %d\n", p[i].p, p[i + 1].p);
      i += 2;
    } while (i < nn - 1 && p[i].y == p[i + 1].y);
  }
  if (q.size() & 1) tr.push_back(q.back()), q.pop_back();
  listprint(q);
}
int main() {
  cin >> n;
  for (int i = 1; i <= n; i++)
    a[i].p = i, scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].z);
  sort(a + 1, a + n + 1);
  vector<point> p;
  for (int i = 1; i <= n;) {
    if (i == n || a[i].x != a[i + 1].x) {
      p.push_back(a[i++]);
      continue;
    }
    vector<point> q;
    for (q.push_back(a[i++]); i <= n && a[i].x == a[i - 1].x; i++)
      q.push_back(a[i]);
    amel(q, p);
  }
  listprint(p);
  return 0;
}
