#include <bits/stdc++.h>
using namespace std;
const int apsz = 26;
const long long o = 1;
const int maxn = 500007;
class node {
 public:
  int x;
  int y;
  int z;
  int id;
  node(int xx = 1, int yy = 1, int zz = 1) { x = xx, y = yy, z = zz; }
  bool operator<(const node& rhs) const { return z < rhs.z; }
};
node ns[maxn];
int n;
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cin >> n;
  for (int i = (0); i < (n); ++i) ns[i].id = i + 1;
  for (int i = (0); i < (n); ++i) cin >> ns[i].x >> ns[i].y >> ns[i].z;
  sort(ns, ns + n);
  vector<node> yu1;
  int l = 0;
  vector<pair<int, int> > ans;
  while (l < n) {
    int r = l;
    while (r < n && ns[r].z == ns[l].z) r++;
    int cnt = r - l;
    sort(ns + l, ns + r, [](const node& a, const node& b) {
      return a.x != b.x ? a.x < b.x : a.y < b.y;
    });
    vector<node> wgr;
    while (l < r) {
      int nr = l;
      int up;
      while (nr < r && ns[l].x == ns[nr].x) nr++;
      if ((nr - l) & 1) wgr.push_back(ns[l]), l++;
      for (int i = l; i < nr; i += 2) ans.push_back({ns[i].id, ns[i + 1].id});
      l = nr;
    }
    int dw;
    if (((int)wgr.size()) & 1)
      dw = 1, yu1.push_back(wgr[0]);
    else
      dw = 0;
    for (int i = dw; i < (int)wgr.size(); i += 2)
      ans.push_back({wgr[i].id, wgr[i + 1].id});
  }
  for (int i = 0; i < (int)yu1.size(); i += 2)
    ans.push_back({yu1[i].id, yu1[i + 1].id});
  for (auto x : ans) cout << x.first << " " << x.second << endl;
  return 0;
}
