#include <bits/stdc++.h>
using namespace std;
long long add(long long a, long long b) {
  a += b;
  if (a >= 1000000007) {
    a -= 1000000007;
  }
  return a;
}
long long sub(long long a, long long b) {
  a -= b;
  if (a < 0) {
    a += 1000000007;
  }
  return a;
}
long long mul(long long a, long long b) { return (a * b) % 1000000007; }
void add_self(long long& a, long long b) { a = add(a, b); }
void sub_self(long long& a, long long b) { a = sub(a, b); }
void mul_self(long long& a, long long b) { a = mul(a, b); }
const long long MAXN = 50010;
const long long CN = 1e9;
pair<pair<long long, long long>, pair<long long, long long>> pts[MAXN];
map<long long, set<long long>> m;
map<long long, multiset<long long>> m2;
long long N;
long long visited[MAXN];
int main() {
  ios_base ::sync_with_stdio(false);
  cin.tie(nullptr);
  cin >> N;
  for (long long i = 0; i < N; i++) {
    cin >> pts[i].first.first >> pts[i].first.second >> pts[i].second.first;
    pts[i].first.first += 1e8;
    pts[i].first.second += 1e8;
    pts[i].second.first += 1e8;
    pts[i].second.second = i;
  }
  sort(pts, pts + N);
  for (long long i = 0; i < N; i++) {
    long long val1 = pts[i].first.first * CN + pts[i].first.second;
    long long val2 = pts[i].second.first * CN + i;
    m[val1].insert(val2);
    m2[pts[i].first.first].insert(pts[i].first.second);
  }
  vector<pair<long long, long long>> ans;
  long long p = 1;
  for (long long i = 0; i < N; i++) {
    if (visited[i]) {
      continue;
    }
    visited[i] = true;
    while (visited[p]) {
      p++;
    }
    long long currx = pts[p].first.first, curry = pts[i].first.second;
    m2[pts[i].first.first].erase(m2[pts[i].first.first].find(curry));
    multiset<long long>::iterator it3 = m2[currx].lower_bound(curry);
    if (it3 == m2[currx].end()) {
      --it3;
    }
    curry = *it3;
    m2[currx].erase(it3);
    long long val1 = pts[p].first.first * CN + curry;
    long long val4 = pts[i].first.first * CN + pts[i].first.second;
    long long val2 = pts[i].second.first * CN + i;
    m[val4].erase(val2);
    set<long long>::iterator it = m[val1].lower_bound(val2);
    if (it == m[val1].end()) {
      --it;
    }
    long long val3 = *it;
    long long z = val3 / CN;
    long long vi = val3 - z * CN;
    m[val1].erase(it);
    visited[vi] = true;
    ans.emplace_back(pts[i].second.second + 1, pts[vi].second.second + 1);
    p++;
  }
  for (long long i = 0; i < ans.size(); i++) {
    cout << ans[i].first << " " << ans[i].second << "\n";
  }
  return 0;
}
