#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using vl = vector<ll>;
using vvl = vector<vl>;
using pll = pair<ll, ll>;
using vpll = vector<pll>;
using vb = vector<bool>;
using vs = vector<string>;
const ll oo = 0x3f3f3f3f3f3f3f3fLL;
const ld eps = 1e-9;
vl x, y, z;
map<ll, map<ll, map<ll, ll>>> points;
bool inside(ll a, ll b, ll c) {
  return x[c] >= min(x[a], x[b]) && x[c] <= max(x[a], x[b]) &&
         y[c] >= min(y[a], y[b]) && y[c] <= max(y[a], y[b]) &&
         z[c] >= min(z[a], z[b]) && z[c] <= max(z[a], z[b]);
}
void eraser(ll i) {
  points[x[i]][y[i]].erase(z[i]);
  if (!ll((points[x[i]][y[i]]).size())) {
    points[x[i]].erase(y[i]);
    if (!ll((points[x[i]]).size())) {
      points.erase(x[i]);
    }
  }
}
int main() {
  cin.sync_with_stdio(0);
  ll n;
  cin >> n;
  x = vl(n);
  y = vl(n);
  z = vl(n);
  for (ll i = (0); i < (n); i++) {
    cin >> x[i] >> y[i] >> z[i];
  }
  for (ll i = (0); i < (n); i++) {
    points[x[i]][y[i]][z[i]] = i;
  }
  vl used(n);
  for (ll i = (0); i < (n); i++) {
    if (used[i]) {
      continue;
    }
    used[i] = true;
    eraser(i);
    auto itx = points.lower_bound(x[i]);
    if (itx == points.end()) {
      itx--;
    }
    auto ity = itx->second.lower_bound(y[i]);
    if (ity == itx->second.end()) {
      ity--;
    }
    auto itz = ity->second.lower_bound(z[i]);
    if (itz == ity->second.end()) {
      itz--;
    }
    ll j = itz->second;
    used[j] = true;
    eraser(j);
    cout << i + 1 << ' ' << j + 1 << endl;
  }
}
