#include <bits/stdc++.h>
using namespace std;
inline int read() {
  char c = getchar();
  int x = 0, f = 1;
  for (; !isdigit(c); c = getchar())
    if (c == '-') f = -1;
  for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
  return x * f;
}
const int MAXN = 1e6 + 5;
struct Point {
  int x, y, z, id;
} p[MAXN], np[MAXN];
int N;
int main() {
  N = read();
  for (int i = 1; i <= N; i++) {
    p[i].x = read();
    p[i].y = read();
    p[i].z = read();
    p[i].id = i;
  }
  sort(p + 1, p + N + 1, [&](Point a, Point b) {
    if (a.x != b.x) return a.x < b.x;
    if (a.y != b.y) return a.y < b.y;
    return a.z < b.z;
  });
  int cnt = 0;
  for (int i = 1; i <= N; i++)
    if (i != 1 && p[i].x == np[cnt].x && p[i].y == np[cnt].y &&
        p[i].z == np[cnt].z) {
      printf("%d %d\n", p[i].id, np[cnt].id);
      cnt--;
    } else
      np[++cnt] = p[i];
  N = cnt;
  cnt = 0;
  for (int i = 1; i <= N; i++) p[i] = np[i];
  for (int i = 1; i <= N; i++)
    if (i != 1 && p[i].x == np[cnt].x && p[i].y == np[cnt].y && cnt) {
      printf("%d %d\n", p[i].id, np[cnt].id);
      cnt--;
    } else
      np[++cnt] = p[i];
  N = cnt;
  cnt = 0;
  for (int i = 1; i <= N; i++) p[i] = np[i];
  for (int i = 1; i <= N; i++)
    if (i != 1 && p[i].x == np[cnt].x && cnt) {
      printf("%d %d\n", p[i].id, np[cnt].id);
      cnt--;
    } else
      np[++cnt] = p[i];
  for (int i = 1; i <= cnt; i += 2) printf("%d %d\n", np[i].id, np[i + 1].id);
  return 0;
}
