#include <bits/stdc++.h>
using namespace std;
const double PI = acos(-1.0);
const long long INF = 1e9;
const long long LINF = INF * INF;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
struct pt {
  int x, y, z, id;
  bool operator<(const pt& p) const {
    if (x != p.x) return x < p.x;
    if (y != p.y) return y < p.y;
    if (z != p.z) return z < p.z;
    return id < p.id;
  }
};
const int N = 1 << 17;
int n;
pt a[N];
int main() {
  ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  cin >> n;
  for (int i = (0); i < (n); ++i) {
    cin >> a[i].x >> a[i].y >> a[i].z;
    a[i].id = i + 1;
  }
  map<int, vector<pt>> mp;
  for (int i = (0); i < (n); ++i) mp[a[i].x].push_back(a[i]);
  for (auto& i : mp) sort(i.second.begin(), i.second.end());
  vector<pair<int, int>> ans;
  for (auto& i : mp) {
    map<int, vector<pt>> mp2;
    for (auto x : i.second) mp2[x.y].push_back(x);
    for (auto& x : mp2) {
      for (int y = 0; y < (int)((x.second).size()) - 1; y += 2)
        ans.push_back({x.second[y].id, x.second[y + 1].id});
      reverse(x.second.begin(), x.second.end());
      x.second.resize((int)((x.second).size()) % 2);
    }
    vector<pt> vec;
    for (auto x : mp2)
      for (auto y : x.second) vec.push_back(y);
    for (int y = 0; y < (int)((vec).size()) - 1; y += 2)
      ans.push_back({vec[y].id, vec[y + 1].id});
    reverse(vec.begin(), vec.end());
    vec.resize((int)((vec).size()) % 2);
    i.second = vec;
  }
  vector<pt> vec;
  for (auto i : mp)
    for (auto j : i.second) vec.push_back(j);
  for (int x = 0; x < (int)((vec).size()); x += 2)
    ans.push_back({vec[x].id, vec[x + 1].id});
  assert((int)((ans).size()) == n / 2);
  for (int i = (0); i < (n >> 1); ++i)
    cout << ans[i].first << ' ' << ans[i].second << '\n';
  cerr << "Time elapsed: " << clock() / (double)CLOCKS_PER_SEC << endl;
  return 0;
}
