#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
const int maxm = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const long long mod = 1e9 + 7;
const int maxblock = sqrt(maxn) + 10;
const double eps = 1e-7;
const long long INF = 1e16;
struct node {
  int x, y, z;
  void input() { scanf("%d %d %d", &x, &y, &z); }
} a[maxn];
map<pair<int, int>, vector<pair<int, int> > > ma1;
map<int, vector<pair<pair<int, int>, int> > > ma2;
vector<int> ma3;
int n;
vector<pair<int, int> > res;
int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) a[i].input();
  for (int i = 1; i <= n; i++) {
    ma1[make_pair(a[i].x, a[i].y)].push_back(make_pair(a[i].z, i));
  }
  for (auto it : ma1) {
    sort(it.second.begin(), it.second.end());
    int sz = it.second.size();
    for (int i = 0; i < sz - 1; i += 2) {
      res.push_back(make_pair(it.second[i].second, it.second[i + 1].second));
    }
    if (it.second.size() % 2 == 1) {
      ma2[it.first.first].push_back(make_pair(
          make_pair(it.first.second, it.second[it.second.size() - 1].first),
          it.second[it.second.size() - 1].second));
    }
  }
  for (auto it : ma2) {
    sort(it.second.begin(), it.second.end());
    int sz = it.second.size();
    for (int i = 0; i < sz - 1; i += 2) {
      res.push_back(make_pair(it.second[i].second, it.second[i + 1].second));
    }
    if (it.second.size() % 2 == 1) {
      ma3.push_back(it.second[it.second.size() - 1].second);
    }
  }
  int sz = ma3.size();
  for (int i = 0; i < sz - 1; i += 2)
    res.push_back(make_pair(ma3[i], ma3[i + 1]));
  for (int i = 0; i < res.size(); i++)
    printf("%d %d\n", res[i].first, res[i].second);
  return 0;
}
