import java.io.*;
import java.math.*;
import java.util.*;

public class Main {
	static final int MOD = 998244353;
	//static final long MOD = 1000000007;
	static boolean[] visited;
    public static void main(String[] args) throws IOException {
        FastScanner sc = new FastScanner();
        int N = sc.nextInt();
        int[][] points = new int[N][4];
        for (int i = 0; i < N; i++) {
        	points[i][0] = i;
        	for (int j = 1; j <= 3; j++)
        		points[i][j] = sc.nextInt();
        }
        boolean[] vis = new boolean[N];
        int[][] ans = new int[N/2][2];
        int index = 0;
        for (int i = 0; i < N-1; i++) {
        	if (vis[i]) continue;
        	int[] diff = {Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE};
        	int match = -1;
        	for (int j = i+1; j < N; j++) {
        		if (vis[j])continue;
        		int[] newDiff = new int[3];
        		for (int d = 0; d < 3; d++)
        			newDiff[d] = Math.abs(points[i][d+1]-points[j][d+1]);
        		if (newDiff[0] < diff[0] || (newDiff[0] == diff[0] && newDiff[1] < diff[1]) || (newDiff[0] == diff[0] && newDiff[1] == diff[1] && newDiff[2] < diff[2])) {
        			diff = newDiff;
        			match = j;
        		}
        	}
        	vis[i] = true;
        	vis[match] = true;
        	ans[index] = new int[]{i+1,match+1};
        	index++;
        }
        StringBuilder print = new StringBuilder();
        for (int i = 0; i < N/2; i++)
        	print.append(ans[i][0] + " " + ans[i][1] + "\n");
        System.out.print(print);
    }

    static class SegmentTreeRMQ {
        int st[]; //array to store segment tree
        int n;

        public SegmentTreeRMQ(int n) {
        	this.n = n;
        }

        // A utility function to get minimum of two numbers
        int minVal(int x, int y) {
            return (x < y) ? x : y;
        }

        // A utility function to get the middle index from corner
        // indexes.
        int getMid(int s, int e) {
            return s + (e - s) / 2;
        }

        /*  A recursive function to get the minimum value in a given
            range of array indexes. The following are parameters for
            this function.

            st    --> Pointer to segment tree
            index --> Index of current node in the segment tree. Initially
                       0 is passed as root is always at index 0
            ss & se  --> Starting and ending indexes of the segment
                         represented by current node, i.e., st[index]
            qs & qe  --> Starting and ending indexes of query range */
        int RMQUtil(int ss, int se, int qs, int qe, int index)
        {
            // If segment of this node is a part of given range, then
            // return the min of the segment
            if (qs <= ss && qe >= se)
                return st[index];

            // If segment of this node is outside the given range
            if (se < qs || ss > qe)
                return Integer.MAX_VALUE;

            // If a part of this segment overlaps with the given range
            int mid = getMid(ss, se);
            return minVal(RMQUtil(ss, mid, qs, qe, 2 * index + 1),
                    RMQUtil(mid + 1, se, qs, qe, 2 * index + 2));
        }

        // Return minimum of elements in range from index qs (quey
        // start) to qe (query end).  It mainly uses RMQUtil()
        int RMQ(int qs, int qe)
        {
            // Check for erroneous input values
            if (qs < 0 || qe > n - 1 || qs > qe) {
                System.out.println("Invalid Input");
                return -1;
            }

            return RMQUtil(0, n - 1, qs, qe, 0);
        }

        // A recursive function that constructs Segment Tree for
        // array[ss..se]. si is index of current node in segment tree st
        int constructSTUtil(int arr[], int ss, int se, int si)
        {
            // If there is one element in array, store it in current
            //  node of segment tree and return
            if (ss == se) {
                st[si] = arr[ss];
                return arr[ss];
            }

            // If there are more than one elements, then recur for left and
            // right subtrees and store the minimum of two values in this node
            int mid = getMid(ss, se);
            st[si] = minVal(constructSTUtil(arr, ss, mid, si * 2 + 1),
                    constructSTUtil(arr, mid + 1, se, si * 2 + 2));
            return st[si];
        }

        /* Function to construct segment tree from given array. This function
           allocates memory for segment tree and calls constructSTUtil() to
           fill the allocated memory */
        void constructST(int arr[])
        {
            // Allocate memory for segment tree

            //Height of segment tree
            int x = (int) (Math.ceil(Math.log(n) / Math.log(2)));

            //Maximum size of segment tree
            int max_size = 2 * (int) Math.pow(2, x) - 1;
            st = new int[max_size]; // allocate memory

            // Fill the allocated memory st
            constructSTUtil(arr, 0, n - 1, 0);
        }
    }

    public static long power(long x, long y, long p) {
        // Initialize result
        long res = 1;

        // Update x if it is more
        // than or equal to p
        x = x % p;

        while (y > 0)
        {
            // If y is odd, multiply x
            // with result
            if((y & 1)==1)
                res = (res * x) % p;

            // y must be even now
            // y = y / 2
            y = y >> 1;
            x = (x * x) % p;
        }
        return res;
    }

    public static long dist(int[] point, int[] point2) {
    	return (long)(Math.pow((point2[1]-point[1]),2)+Math.pow((point2[0]-point[0]),2));
    }

    public static long gcd(long a, long b) {
    	if (b == 0)
    		return a;
    	else
    		return gcd(b,a%b);
    }

    public static int[][] sort(int[][] array) {
    	//Sort an array (immune to quicksort TLE)
		Random rgen = new Random();
		for (int i = 0; i < array.length; i++) {
		    int randomPosition = rgen.nextInt(array.length);
		    int[] temp = array[i];
		    array[i] = array[randomPosition];
		    array[randomPosition] = temp;
		}
		Arrays.sort(array, new Comparator<int[]>() {
			  @Override
        	  public int compare(int[] arr1, int[] arr2) {
				  if (arr1[1] != arr2[1])
					  return arr1[1]-arr2[1];
				  else if (arr1[2] != arr2[2])
					  return arr1[2]-arr2[2];
				  else
					  return arr1[3]-arr2[3];
	          }
		});
		return array;
	}

    static class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException  e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }

        String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }
}
class Node {
	public HashSet<Node> children;
	public int n;

	public Node(int n) {
		this.n = n;
		children = new HashSet<Node>();
	}

	public void addChild(Node node) {
		children.add(node);
	}

	public void removeChild(Node node) {
		children.remove(node);
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return n;
	}

	@Override
	public boolean equals(Object obj) {
		if (! (obj instanceof Node)) {
			return false;
		} else {
			Node node = (Node) obj;
			return (n == node.n);
		}
	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.Comparator;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author lewin
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        C1BalancedRemovalsEasier solver = new C1BalancedRemovalsEasier();
        solver.solve(1, in, out);
        out.close();
    }

    static class C1BalancedRemovalsEasier {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.nextInt();
            ArrayList<C1BalancedRemovalsEasier.Point> ps = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                ps.add(new C1BalancedRemovalsEasier.Point(in.nextInt(), in.nextInt(), in.nextInt(), i + 1));
            }
            for (int i = 0; i < 3; i++) {
                for (int j = i + 1; j < 3; j++) {
                    int r = 3 - i - j;
                    ps.sort(Comparator.comparingInt(x -> x.cs[r]));
                    HashMap<Pair<Integer, Integer>, C1BalancedRemovalsEasier.Point> mp = new HashMap<>();
                    for (C1BalancedRemovalsEasier.Point x : ps) {
                        Pair<Integer, Integer> k = new Pair<>(x.cs[i], x.cs[j]);
                        if (mp.containsKey(k)) {
                            C1BalancedRemovalsEasier.Point v = mp.remove(k);
                            out.println(x.idx + " " + v.idx);
                        } else {
                            mp.put(k, x);
                        }
                    }
                    ps = new ArrayList<>(mp.values());
                }
            }
            for (int i = 0; i < 3; i++) {
                if (i == 0) {
                    final int i1 = 1, i2 = 2;
                    ps.sort((a, b) -> (a.cs[i1] == b.cs[i1] ? a.cs[i2] - b.cs[i2] : a.cs[i1] - b.cs[i1]));
                } else if (i == 1) {
                    final int i1 = 0, i2 = 2;
                    ps.sort((a, b) -> (a.cs[i1] == b.cs[i1] ? a.cs[i2] - b.cs[i2] : a.cs[i1] - b.cs[i1]));
                } else {
                    final int i1 = 0, i2 = 1;
                    ps.sort((a, b) -> (a.cs[i1] == b.cs[i1] ? a.cs[i2] - b.cs[i2] : a.cs[i1] - b.cs[i1]));
                }

                HashMap<Integer, C1BalancedRemovalsEasier.Point> mp = new HashMap<>();
                for (C1BalancedRemovalsEasier.Point x : ps) {
                    if (mp.containsKey(x.cs[i])) {
                        C1BalancedRemovalsEasier.Point v = mp.remove(x.cs[i]);
                        out.println(x.idx + " " + v.idx);
                    } else {
                        mp.put(x.cs[i], x);
                    }
                }
                ps = new ArrayList<>(mp.values());

            }
            ps.sort((a, b) -> (a.cs[0] == b.cs[0] ? (a.cs[1] == b.cs[1] ? a.cs[2] - a.cs[2] : a.cs[1] - b.cs[1]) : a.cs[0] - b.cs[0]));
            for (int i = 0; i < ps.size(); i += 2) {
                out.println(ps.get(i).idx + " " + ps.get(i + 1).idx);
            }
        }

        static class Point {
            public int idx;
            public int[] cs;

            public Point(int x, int y, int z, int idx) {
                cs = new int[]{x, y, z};
                this.idx = idx;
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void println(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1 << 16];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (this.numChars == -1) {
                throw new InputMismatchException();
            } else {
                if (this.curChar >= this.numChars) {
                    this.curChar = 0;

                    try {
                        this.numChars = this.stream.read(this.buf);
                    } catch (IOException var2) {
                        throw new InputMismatchException();
                    }

                    if (this.numChars <= 0) {
                        return -1;
                    }
                }

                return this.buf[this.curChar++];
            }
        }

        public int nextInt() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            int res = 0;

            while (c >= 48 && c <= 57) {
                res *= 10;
                res += c - 48;
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * sgn;
                }
            }

            throw new InputMismatchException();
        }

        public static boolean isSpaceChar(int c) {
            return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
        }

    }

    static class Pair<U extends Comparable<U>, V extends Comparable<V>> implements Comparable<Pair<U, V>> {
        public final U u;
        public final V v;

        public Pair(U u, V v) {
            this.u = u;
            this.v = v;
        }

        public int hashCode() {
            return (u == null ? 0 : u.hashCode() * 31) + (v == null ? 0 : v.hashCode());
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClass() != o.getClass())
                return false;
            Pair<U, V> p = (Pair<U, V>) o;
            return (u == null ? p.u == null : u.equals(p.u)) && (v == null ? p.v == null : v.equals(p.v));
        }

        public int compareTo(Pair<U, V> b) {
            int cmpU = u.compareTo(b.u);
            return cmpU != 0 ? cmpU : v.compareTo(b.v);
        }

        public String toString() {
            return String.format("[Pair = (%s, %s)", u.toString(), v.toString());
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Rustam Musin (t.me/musin_acm)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        C1SbalansirovannieUdaleniyaPoproshe solver = new C1SbalansirovannieUdaleniyaPoproshe();
        solver.solve(1, in, out);
        out.close();
    }

    static class C1SbalansirovannieUdaleniyaPoproshe {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            C1SbalansirovannieUdaleniyaPoproshe.Point[] a = new C1SbalansirovannieUdaleniyaPoproshe.Point[n];
            for (int i = 0; i < n; i++) {
                a[i] = new C1SbalansirovannieUdaleniyaPoproshe.Point(i, in.readInt(), in.readInt(), in.readInt());
            }
            Arrays.sort(a);
            boolean[] removed = new boolean[n];
            for (int i = 0; i < n; i++) {
                int j = i;
                while (j + 1 < n && a[i].x == a[j + 1].x) j++;
                int k = j;
                while (k > i) {
                    out.printLine(a[k - 1].idx + 1, a[k].idx + 1);
                    removed[k - 1] = removed[k] = true;
                    k -= 2;
                }
                i = j;
            }
            List<Integer> unremoved = new ArrayList<>();
            for (int i = 0; i < n; i++) if (!removed[i]) unremoved.add(i);
            for (int i = 0; i < unremoved.size(); i += 2) {
                int x = a[unremoved.get(i)].idx;
                int y = a[unremoved.get(i + 1)].idx;
                out.printLine(x + 1, y + 1);
            }
        }

        static class Point implements Comparable<C1SbalansirovannieUdaleniyaPoproshe.Point> {
            long x;
            long y;
            long z;
            int idx;

            public Point(int i, long x, long y, long z) {
                idx = i;
                this.x = x;
                this.y = y;
                this.z = z;
            }

            public int compareTo(C1SbalansirovannieUdaleniyaPoproshe.Point o) {
                int c = Long.compare(x, o.x);
                if (c == 0) c = Long.compare(y, o.y);
                if (c == 0) c = Long.compare(z, o.z);
                return c;
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void printLine(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Rustam Musin (t.me/musin_acm)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        C1SbalansirovannieUdaleniyaPoproshe solver = new C1SbalansirovannieUdaleniyaPoproshe();
        solver.solve(1, in, out);
        out.close();
    }

    static class C1SbalansirovannieUdaleniyaPoproshe {
        C1SbalansirovannieUdaleniyaPoproshe.Point[] a;
        List<IntIntPair> answer;

        void save(int i, int j) {
            answer.add(IntIntPair.makePair(i, j));
        }

        List<Integer> dfs(int l, int r, int t) {
            List<Integer> results = new ArrayList<>();
            if (t == 3) {
                for (int i = l; i <= r; i++) results.add(i);
                return results;
            }

            for (int i = l; i <= r; i++) {
                int j = i;
                while (j + 1 <= r && a[j + 1].a[t] == a[i].a[t]) j++;
                results.addAll(dfs(i, j, t + 1));
                i = j;
            }
            while (results.size() > 1) {
                int x = results.get(results.size() - 2);
                int y = results.get(results.size() - 1);
                save(x, y);
                results.remove(results.size() - 1);
                results.remove(results.size() - 1);
            }
            return results;
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            a = new C1SbalansirovannieUdaleniyaPoproshe.Point[n];
            for (int i = 0; i < n; i++)
                a[i] = new C1SbalansirovannieUdaleniyaPoproshe.Point(i, in.readInt(), in.readInt(), in.readInt());
            Arrays.sort(a);
            answer = new ArrayList<>();
            dfs(0, n - 1, 0);
            for (IntIntPair p : answer) out.printLine(a[p.first].idx + 1, a[p.second].idx + 1);
        }

        static class Point implements Comparable<C1SbalansirovannieUdaleniyaPoproshe.Point> {
            int[] a;
            int idx;

            public Point(int i, int... a) {
                idx = i;
                this.a = a;
            }

            public int compareTo(C1SbalansirovannieUdaleniyaPoproshe.Point o) {
                for (int i = 0; i < a.length; i++) if (a[i] != o.a[i]) return Integer.compare(a[i], o.a[i]);
                return 0;
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void printLine(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class IntIntPair implements Comparable<IntIntPair> {
        public final int first;
        public final int second;

        public static IntIntPair makePair(int first, int second) {
            return new IntIntPair(first, second);
        }

        public IntIntPair(int first, int second) {
            this.first = first;
            this.second = second;
        }

        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            IntIntPair pair = (IntIntPair) o;

            return first == pair.first && second == pair.second;
        }

        public int hashCode() {
            int result = first;
            result = 31 * result + second;
            return result;
        }

        public String toString() {
            return "(" + first + "," + second + ")";
        }

        public int compareTo(IntIntPair o) {
            int value = Integer.compare(first, o.first);
            if (value != 0) {
                return value;
            }
            return Integer.compare(second, o.second);
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Rustam Musin (t.me/musin_acm)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        C1SbalansirovannieUdaleniyaPoproshe solver = new C1SbalansirovannieUdaleniyaPoproshe();
        solver.solve(1, in, out);
        out.close();
    }

    static class C1SbalansirovannieUdaleniyaPoproshe {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            C1SbalansirovannieUdaleniyaPoproshe.Point[] a = new C1SbalansirovannieUdaleniyaPoproshe.Point[n];
            for (int i = 0; i < n; i++) {
                a[i] = new C1SbalansirovannieUdaleniyaPoproshe.Point(i, in.readInt(), in.readInt(), in.readInt());
            }
            Arrays.sort(a);
            for (int i = 0; i < n; i += 2) {
                out.printLine(a[i].idx + 1, a[i + 1].idx + 1);
            }
        }

        static class Point implements Comparable<C1SbalansirovannieUdaleniyaPoproshe.Point> {
            long x;
            long y;
            long z;
            int idx;

            public Point(int i, long x, long y, long z) {
                idx = i;
                this.x = x;
                this.y = y;
                this.z = z;
            }

            public int compareTo(C1SbalansirovannieUdaleniyaPoproshe.Point o) {
                int c = Long.compare(x, o.x);
                if (c == 0) c = Long.compare(y, o.y);
                if (c == 0) c = Long.compare(z, o.z);
                return c;
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void printLine(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.util.Collection;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.Deque;
import java.util.TreeSet;
import java.util.ArrayList;
import java.util.List;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.ArrayDeque;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Rustam Musin (t.me/musin_acm)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        C1SbalansirovannieUdaleniyaPoproshe solver = new C1SbalansirovannieUdaleniyaPoproshe();
        solver.solve(1, in, out);
        out.close();
    }

    static class C1SbalansirovannieUdaleniyaPoproshe {
        private TreeSet<Integer> active;
        private Deque<Integer> q;
        C1SbalansirovannieUdaleniyaPoproshe.Point[] a;

        boolean canUse(int i) {
            if (!active.contains(i)) return false;
            Integer j = active.higher(i);
            if (j == null) return false;
            if (active.lower(i) != null && check(i, j, active.lower(i))) return false;
            if (active.higher(j) != null && check(i, j, active.higher(j))) return false;
            return true;
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            List<IntIntPair> answer = new ArrayList<>(n / 2);
            a = new C1SbalansirovannieUdaleniyaPoproshe.Point[n];
            for (int i = 0; i < n; i++) {
                a[i] = new C1SbalansirovannieUdaleniyaPoproshe.Point(i, in.readInt(), in.readInt(), in.readInt());
            }
            Arrays.sort(a);
            active = new TreeSet<>();
            q = new ArrayDeque<>();
            for (int i = 0; i < n; i++) active.add(i);
            for (int i = 0; i < n; i++) q.add(i);
            while (!q.isEmpty()) {
                int cur = q.poll();
                if (!canUse(cur)) continue;
                int next = active.higher(cur);
                answer.add(IntIntPair.makePair(a[cur].idx, a[next].idx));
                active.remove(cur);
                active.remove(next);
                Integer higher = active.higher(next);
                if (higher != null && canUse(next)) q.add(higher);
                Integer lower1 = active.lower(cur);
                if (lower1 != null) {
                    if (canUse(lower1)) q.add(lower1);
                    Integer lower2 = active.lower(lower1);
                    if (lower2 != null && canUse(lower2)) q.add(lower2);
                }
            }
//        if (!check(a, answer)) throw new OutOfMemoryError("NO");
            for (IntIntPair p : answer) out.printLine(p.first + 1, p.second + 1);
        }

        boolean check(int i, int j, int k) {
            return check(a[i], a[j], a[k]);
        }

        boolean check(C1SbalansirovannieUdaleniyaPoproshe.Point a, C1SbalansirovannieUdaleniyaPoproshe.Point b, C1SbalansirovannieUdaleniyaPoproshe.Point c) {
            return between(a.x, b.x, c.x) && between(a.y, b.y, c.y) && between(a.z, b.z, c.z);
        }

        boolean between(long a, long b, long c) {
            return Math.min(a, b) <= c && c <= Math.max(a, b);
        }

        static class Point implements Comparable<C1SbalansirovannieUdaleniyaPoproshe.Point> {
            long x;
            long y;
            long z;
            int idx;

            public Point(int i, long x, long y, long z) {
                idx = i;
                this.x = x;
                this.y = y;
                this.z = z;
            }

            public int compareTo(C1SbalansirovannieUdaleniyaPoproshe.Point o) {
                int c = Long.compare(x, o.x);
                if (c == 0) c = Long.compare(y, o.y);
                if (c == 0) c = Long.compare(z, o.z);
                return c;
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void printLine(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class IntIntPair implements Comparable<IntIntPair> {
        public final int first;
        public final int second;

        public static IntIntPair makePair(int first, int second) {
            return new IntIntPair(first, second);
        }

        public IntIntPair(int first, int second) {
            this.first = first;
            this.second = second;
        }

        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            IntIntPair pair = (IntIntPair) o;

            return first == pair.first && second == pair.second;
        }

        public int hashCode() {
            int result = first;
            result = 31 * result + second;
            return result;
        }

        public String toString() {
            return "(" + first + "," + second + ")";
        }

        public int compareTo(IntIntPair o) {
            int value = Integer.compare(first, o.first);
            if (value != 0) {
                return value;
            }
            return Integer.compare(second, o.second);
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Rustam Musin (t.me/musin_acm)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        C1SbalansirovannieUdaleniyaPoproshe solver = new C1SbalansirovannieUdaleniyaPoproshe();
        solver.solve(1, in, out);
        out.close();
    }

    static class C1SbalansirovannieUdaleniyaPoproshe {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            List<IntIntPair> answer = new ArrayList<>(n / 2);
            C1SbalansirovannieUdaleniyaPoproshe.Point[] a = new C1SbalansirovannieUdaleniyaPoproshe.Point[n];
            for (int i = 0; i < n; i++) {
                a[i] = new C1SbalansirovannieUdaleniyaPoproshe.Point(i, in.readInt(), in.readInt(), in.readInt());
            }
            Arrays.sort(a);
            boolean[] removed = new boolean[n];
            for (int i = 0; i < n; i++) {
                int j = i;
                while (j + 1 < n && a[i].x == a[j + 1].x) j++;
                int l = i;
                int r = j;
                while (r - l + 1 >= 2) {
                    if (l + 1 == r || !check(a[l], a[l + 1], a[l + 2])) {
                        answer.add(IntIntPair.makePair(a[l].idx, a[l + 1].idx));
                        removed[l] = removed[l + 1] = true;
                        l += 2;
                    } else {
                        answer.add(IntIntPair.makePair(a[r - 1].idx, a[r].idx));
                        removed[r - 1] = removed[r] = true;
                        r -= 2;
                    }
                }
                i = j;
            }
            List<Integer> unremoved = new ArrayList<>();
            for (int i = 0; i < n; i++) if (!removed[i]) unremoved.add(i);
            for (int i = 0; i < unremoved.size(); i += 2) {
                int x = a[unremoved.get(i)].idx;
                int y = a[unremoved.get(i + 1)].idx;
                answer.add(IntIntPair.makePair(x, y));
            }
            if (!check(a, answer)) throw new OutOfMemoryError("NO");
            for (IntIntPair p : answer) out.printLine(p.first + 1, p.second + 1);
        }

        boolean check(C1SbalansirovannieUdaleniyaPoproshe.Point[] a, List<IntIntPair> order) {
            int n = a.length;
            boolean[] active = new boolean[n];
            for (IntIntPair p : order) {
                for (int i = 0; i < n; i++) {
                    if (active[i] && i != p.first && i != p.second && check(a[p.first], a[p.second], a[i])) {
                        return false;
                    }
                }
                active[p.first] = active[p.second] = false;
            }
            return true;
        }

        boolean check(C1SbalansirovannieUdaleniyaPoproshe.Point a, C1SbalansirovannieUdaleniyaPoproshe.Point b, C1SbalansirovannieUdaleniyaPoproshe.Point c) {
            return between(a.x, b.x, c.x) && between(a.y, b.y, c.y) && between(a.z, b.z, c.z);
        }

        boolean between(long a, long b, long c) {
            return Math.min(a, b) <= c && c <= Math.max(a, b);
        }

        static class Point implements Comparable<C1SbalansirovannieUdaleniyaPoproshe.Point> {
            long x;
            long y;
            long z;
            int idx;

            public Point(int i, long x, long y, long z) {
                idx = i;
                this.x = x;
                this.y = y;
                this.z = z;
            }

            public int compareTo(C1SbalansirovannieUdaleniyaPoproshe.Point o) {
                int c = Long.compare(x, o.x);
                if (c == 0) c = Long.compare(y, o.y);
                if (c == 0) c = Long.compare(z, o.z);
                return c;
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void printLine(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class IntIntPair implements Comparable<IntIntPair> {
        public final int first;
        public final int second;

        public static IntIntPair makePair(int first, int second) {
            return new IntIntPair(first, second);
        }

        public IntIntPair(int first, int second) {
            this.first = first;
            this.second = second;
        }

        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            IntIntPair pair = (IntIntPair) o;

            return first == pair.first && second == pair.second;
        }

        public int hashCode() {
            int result = first;
            result = 31 * result + second;
            return result;
        }

        public String toString() {
            return "(" + first + "," + second + ")";
        }

        public int compareTo(IntIntPair o) {
            int value = Integer.compare(first, o.first);
            if (value != 0) {
                return value;
            }
            return Integer.compare(second, o.second);
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.util.Collection;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.Queue;
import java.util.ArrayDeque;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Rustam Musin (t.me/musin_acm)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        C1SbalansirovannieUdaleniyaPoproshe solver = new C1SbalansirovannieUdaleniyaPoproshe();
        solver.solve(1, in, out);
        out.close();
    }

    static class C1SbalansirovannieUdaleniyaPoproshe {
        C1SbalansirovannieUdaleniyaPoproshe.Point[] a;
        List<IntIntPair> answer;

        void save(int i, int j) {
            answer.add(IntIntPair.makePair(i, j));
        }

        Queue<Integer> dfs(int l, int r, int t) {
            Queue<Integer> results = new ArrayDeque<>();
            if (t == 3) {
                for (int i = l; i <= r; i++) results.add(i);
                return results;
            }

            for (int i = l; i <= r; i++) {
                int j = i;
                while (j + 1 <= r && a[j + 1].a[t] == a[i].a[t]) j++;
                results.addAll(dfs(i, j, t + 1));
                i = j;
            }
            while (results.size() > 1) save(results.poll(), results.poll());
            return results;
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            a = new C1SbalansirovannieUdaleniyaPoproshe.Point[n];
            for (int i = 0; i < n; i++)
                a[i] = new C1SbalansirovannieUdaleniyaPoproshe.Point(i, in.readInt(), in.readInt(), in.readInt());
            Arrays.sort(a);
            answer = new ArrayList<>();
            dfs(0, n - 1, 0);
            for (IntIntPair p : answer) out.printLine(a[p.first].idx + 1, a[p.second].idx + 1);
        }

        static class Point implements Comparable<C1SbalansirovannieUdaleniyaPoproshe.Point> {
            int[] a;
            int idx;

            public Point(int i, int... a) {
                idx = i;
                this.a = a;
            }

            public int compareTo(C1SbalansirovannieUdaleniyaPoproshe.Point o) {
                for (int i = 0; i < a.length; i++) if (a[i] != o.a[i]) return Integer.compare(a[i], o.a[i]);
                return 0;
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void printLine(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class IntIntPair implements Comparable<IntIntPair> {
        public final int first;
        public final int second;

        public static IntIntPair makePair(int first, int second) {
            return new IntIntPair(first, second);
        }

        public IntIntPair(int first, int second) {
            this.first = first;
            this.second = second;
        }

        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            IntIntPair pair = (IntIntPair) o;

            return first == pair.first && second == pair.second;
        }

        public int hashCode() {
            int result = first;
            result = 31 * result + second;
            return result;
        }

        public String toString() {
            return "(" + first + "," + second + ")";
        }

        public int compareTo(IntIntPair o) {
            int value = Integer.compare(first, o.first);
            if (value != 0) {
                return value;
            }
            return Integer.compare(second, o.second);
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Rustam Musin (t.me/musin_acm)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        C1SbalansirovannieUdaleniyaPoproshe solver = new C1SbalansirovannieUdaleniyaPoproshe();
        solver.solve(1, in, out);
        out.close();
    }

    static class C1SbalansirovannieUdaleniyaPoproshe {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            List<IntIntPair> answer = new ArrayList<>(n / 2);
            C1SbalansirovannieUdaleniyaPoproshe.Point[] a = new C1SbalansirovannieUdaleniyaPoproshe.Point[n];
            for (int i = 0; i < n; i++) {
                a[i] = new C1SbalansirovannieUdaleniyaPoproshe.Point(i, in.readInt(), in.readInt(), in.readInt());
            }
            Arrays.sort(a);
            boolean[] removed = new boolean[n];
            for (int i = 0; i < n; i++) {
                int j = i;
                while (j + 1 < n && a[i].x == a[j + 1].x) j++;
                int l = i;
                int r = j;
                List<Integer> vars = new ArrayList<>();
                for (int k = i; k <= j; k++) vars.add(k);
                while (vars.size() > 1) {
                    int y = vars.get(vars.size() - 2);
                    int z = vars.get(vars.size() - 1);
                    int x;
                    if (vars.size() == 2 || check(a[x = vars.get(vars.size() - 3)], a[y], a[z])) {
                        answer.add(IntIntPair.makePair(a[y].idx, a[z].idx));
                        removed[y] = removed[z] = true;
                        vars.remove(vars.size() - 1);
                        vars.remove(vars.size() - 1);
                    } else {
                        answer.add(IntIntPair.makePair(a[x].idx, a[y].idx));
                        removed[x] = removed[y] = true;
                        vars.remove(vars.size() - 2);
                        vars.remove(vars.size() - 2);
                    }
                }
                i = j;
            }
            List<Integer> unremoved = new ArrayList<>();
            for (int i = 0; i < n; i++) if (!removed[i]) unremoved.add(i);
            for (int i = 0; i < unremoved.size(); i += 2) {
                int x = a[unremoved.get(i)].idx;
                int y = a[unremoved.get(i + 1)].idx;
                answer.add(IntIntPair.makePair(x, y));
            }
            if (!check(a, answer)) throw new OutOfMemoryError("NO");
            for (IntIntPair p : answer) out.printLine(p.first + 1, p.second + 1);
        }

        boolean check(C1SbalansirovannieUdaleniyaPoproshe.Point[] a, List<IntIntPair> order) {
            int n = a.length;
            boolean[] active = new boolean[n];
            for (IntIntPair p : order) {
                for (int i = 0; i < n; i++) {
                    if (active[i] && i != p.first && i != p.second && check(a[p.first], a[p.second], a[i])) {
                        return false;
                    }
                }
                active[p.first] = active[p.second] = false;
            }
            return true;
        }

        boolean check(C1SbalansirovannieUdaleniyaPoproshe.Point a, C1SbalansirovannieUdaleniyaPoproshe.Point b, C1SbalansirovannieUdaleniyaPoproshe.Point c) {
            return between(a.x, b.x, c.x) && between(a.y, b.y, c.y) && between(a.z, b.z, c.z);
        }

        boolean between(long a, long b, long c) {
            return Math.min(a, b) <= c && c <= Math.max(a, b);
        }

        static class Point implements Comparable<C1SbalansirovannieUdaleniyaPoproshe.Point> {
            long x;
            long y;
            long z;
            int idx;

            public Point(int i, long x, long y, long z) {
                idx = i;
                this.x = x;
                this.y = y;
                this.z = z;
            }

            public int compareTo(C1SbalansirovannieUdaleniyaPoproshe.Point o) {
                int c = Long.compare(x, o.x);
                if (c == 0) c = Long.compare(y, o.y);
                if (c == 0) c = Long.compare(z, o.z);
                return c;
            }

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void print(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(objects[i]);
            }
        }

        public void printLine(Object... objects) {
            print(objects);
            writer.println();
        }

        public void close() {
            writer.close();
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class IntIntPair implements Comparable<IntIntPair> {
        public final int first;
        public final int second;

        public static IntIntPair makePair(int first, int second) {
            return new IntIntPair(first, second);
        }

        public IntIntPair(int first, int second) {
            this.first = first;
            this.second = second;
        }

        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            IntIntPair pair = (IntIntPair) o;

            return first == pair.first && second == pair.second;
        }

        public int hashCode() {
            int result = first;
            result = 31 * result + second;
            return result;
        }

        public String toString() {
            return "(" + first + "," + second + ")";
        }

        public int compareTo(IntIntPair o) {
            int value = Integer.compare(first, o.first);
            if (value != 0) {
                return value;
            }
            return Integer.compare(second, o.second);
        }

    }
}


import java.io.*;
import java.math.BigInteger;
import java.util.*;

public class Main {
    static int MOD = 1000000007;

    // After writing solution, quick scan for:
    //   array out of bounds
    //   special cases e.g. n=1?
    //
    // Big numbers arithmetic bugs:
    //   int overflow
    //   sorting, or taking max, after MOD
    void solve() throws IOException {
        int n = ri();
        int[][] points = new int[n][4];
        for (int i = 0; i < n; i++) {
            int[] xyz = ril(3);
            System.arraycopy(xyz, 0, points[i], 0, 3);
            points[i][3] = i+1;
        }
        Map<Integer, List<int[]>> planes = new HashMap<>();
        for (int[] p : points) {
            int z = p[2];
            if (!planes.containsKey(z)) planes.put(z, new ArrayList<>());
            planes.get(z).add(p);
        }
        List<int[]> newPoints = new ArrayList<>();
        for (int z : planes.keySet()) {
            int[] ret = solvePlane(planes.get(z));
            if (ret != null) newPoints.add(ret);
        }
        solveLine(newPoints, 2);
    }

    int[] solvePlane(List<int[]> points) {
        Map<Integer, List<int[]>> lines = new HashMap<>();
        for (int[] p : points) {
            int y = p[1];
            if (!lines.containsKey(y)) lines.put(y, new ArrayList<>());
            lines.get(y).add(p);
        }
        List<int[]> newPoints = new ArrayList<>();
        for (int y : lines.keySet()) {
            int[] ret = solveLine(lines.get(y), 0);
            if (ret != null) newPoints.add(ret);
        }
        return solveLine(newPoints, 1);
    }

    int[] solveLine(List<int[]> points, int axis) {
        Collections.sort(points, (p1, p2) -> Integer.compare(p1[axis], p2[axis]));
        for (int i = points.size()-2; i >= 0; i -= 2) {
            int i1 = points.get(i+1)[3];
            int i2 = points.get(i)[3];
            points.remove(i+1);
            points.remove(i);
            pw.println(i1 + " " + i2);
        }
        return points.isEmpty() ? null : points.get(0);
    }

    // Template code below

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    PrintWriter pw = new PrintWriter(System.out);

    public static void main(String[] args) throws IOException {
        Main m = new Main();
        m.solve();
        m.close();
    }

    void close() throws IOException {
        pw.flush();
        pw.close();
        br.close();
    }

    int ri() throws IOException {
        return Integer.parseInt(br.readLine());
    }

    long rl() throws IOException {
        return Long.parseLong(br.readLine());
    }

    int[] ril(int n) throws IOException {
        int[] nums = new int[n];
        int c = 0;
        for (int i = 0; i < n; i++) {
            int sign = 1;
            c = br.read();
            int x = 0;
            if (c == '-') {
                sign = -1;
                c = br.read();
            }
            while (c >= '0' && c <= '9') {
                x = x * 10 + c - '0';
                c = br.read();
            }
            nums[i] = x * sign;
        }
        while (c != '\n' && c != -1) c = br.read();
        return nums;
    }

    long[] rll(int n) throws IOException {
        long[] nums = new long[n];
        int c = 0;
        for (int i = 0; i < n; i++) {
            int sign = 1;
            c = br.read();
            long x = 0;
            if (c == '-') {
                sign = -1;
                c = br.read();
            }
            while (c >= '0' && c <= '9') {
                x = x * 10 + c - '0';
                c = br.read();
            }
            nums[i] = x * sign;
        }
        while (c != '\n' && c != -1) c = br.read();
        return nums;
    }

    char[] rs() throws IOException {
        return br.readLine().toCharArray();
    }

    void sort(int[] A) {
        Random r = new Random();
        for (int i = A.length-1; i > 0; i--) {
            int j = r.nextInt(i+1);
            int temp = A[i];
            A[i] = A[j];
            A[j] = temp;
        }
        Arrays.sort(A);
    }

    int max(int a, int b) {
        return a >= b ? a : b;
    }

    int min(int a, int b) {
        return a <= b ? a : b;
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.FilterInputStream;
import java.io.BufferedInputStream;
import java.util.Random;
import java.util.Comparator;
import java.util.ArrayList;
import java.io.InputStream;

/**
 * @author khokharnikunj8
 */

public class Main {
    public static void main(String[] args) {
        new Thread(null, new Runnable() {
            public void run() {
                new Main().solve();
            }
        }, "1", 1 << 26).start();
    }

    void solve() {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        ScanReader in = new ScanReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        C1BalancedRemovalsEasier solver = new C1BalancedRemovalsEasier();
        solver.solve(1, in, out);
        out.close();
    }

    static class C1BalancedRemovalsEasier {
        public void solve(int testNumber, ScanReader in, PrintWriter out) {
            int n = in.scanInt();
            int[][] ar = new int[n][4];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < 3; j++) ar[i][j] = in.scanInt();
                ar[i][3] = i + 1;
            }
            CodeHash.shuffle(ar);
            Arrays.sort(ar, new Comparator<int[]>() {

                public int compare(int[] o1, int[] o2) {
                    if (o1[0] == o2[0]) {
                        if (o1[1] == o2[1]) {
                            return o1[2] - o2[2];
                        } else return o1[1] - o2[1];
                    } else return o1[0] - o2[0];
                }
            });

            ArrayList<int[]> ans = new ArrayList<>();
            boolean[] done = new boolean[n];
            for (int i = 1; i < n; i++) {
                boolean check = (!done[i - 1]);
                for (int j = 0; j < 2; j++) {
                    check &= (ar[i][j] == ar[i - 1][j]);
                }
                if (check) {
                    done[i - 1] = true;
                    done[i] = true;
                    ans.add(new int[]{ar[i - 1][3], ar[i][3]});
                }
            }
            ArrayList<int[]> remaining1 = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                if (!done[i]) remaining1.add(ar[i]);
            }
            boolean[] done1 = new boolean[remaining1.size()];
            for (int i = 1; i < remaining1.size(); i++) {
                boolean check = (!done1[i - 1]);
                for (int j = 0; j < 1; j++) {
                    check &= (remaining1.get(i)[j] == remaining1.get(i - 1)[j]);
                }
                if (check) {
                    done1[i - 1] = true;
                    done1[i] = true;
                    ans.add(new int[]{remaining1.get(i - 1)[3], remaining1.get(i)[3]});
                }
            }
            ArrayList<int[]> remaining2 = new ArrayList<>();
            for (int i = 0; i < remaining1.size(); i++) {
                if (!done1[i]) remaining2.add(remaining1.get(i));
            }
            for (int i = 0; i < remaining2.size(); i += 2) {
                ans.add(new int[]{remaining2.get(i)[3], remaining2.get(i + 1)[3]});
            }
            for (int[] p : ans) out.println(p[0] + " " + p[1]);

        }

    }

    static class CodeHash {
        public static void shuffle(int[][] ar) {
            Random rd = new Random(new Random().nextInt());
            for (int i = 0; i < ar.length; i++) {
                int index = rd.nextInt(ar.length);
                int[] temp = ar[i];
                ar[i] = ar[index];
                ar[index] = temp;
            }
        }

    }

    static class ScanReader {
        private byte[] buf = new byte[4 * 1024];
        private int index;
        private BufferedInputStream in;
        private int total;

        public ScanReader(InputStream inputStream) {
            in = new BufferedInputStream(inputStream);
        }

        private int scan() {
            if (index >= total) {
                index = 0;
                try {
                    total = in.read(buf);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (total <= 0) return -1;
            }
            return buf[index++];
        }

        public int scanInt() {
            int integer = 0;
            int n = scan();
            while (isWhiteSpace(n)) n = scan();
            int neg = 1;
            if (n == '-') {
                neg = -1;
                n = scan();
            }
            while (!isWhiteSpace(n)) {
                if (n >= '0' && n <= '9') {
                    integer *= 10;
                    integer += n - '0';
                    n = scan();
                }
            }
            return neg * integer;
        }

        private boolean isWhiteSpace(int n) {
            if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true;
            else return false;
        }

    }
}


import java.util.*;
import java.lang.*;
import java.io.*;

public class Main
{
	PrintWriter out = new PrintWriter(System.out);
	BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer tok = new StringTokenizer("");
    String next() throws IOException {
        if (!tok.hasMoreTokens()) { tok = new StringTokenizer(in.readLine()); }
        return tok.nextToken();
    }
    int ni() throws IOException { return Integer.parseInt(next()); }
    long nl() throws IOException { return Long.parseLong(next()); }

    void solve() throws IOException {
        int n=ni();
        int[][]A=new int[n][4];
        for (int x=1;x<=n;x++) {
            A[x-1][0]=ni();
            A[x-1][1]=ni();
            A[x-1][2]=ni();
            A[x-1][3]=x;
        }
        Arrays.sort(A, (a,b)-> {
            if (a[0]==b[0] && a[1]==b[1]) return a[2]-b[2];
            else {
                if (a[0]==b[0]) return a[1]-b[1];
                else return a[0]-b[0];
            }
        });

        int sv=0;
        boolean sf=false;
        int p=0;
        int q=0;
        int ct=0;

        while (p<n) {
            ct=0;
            q=p;
            while (q<n && A[q][0]==A[p][0]) { ct++; q++; }

            if (ct==1) {
                if (sf) {
                    out.println(sv+" "+A[p][3]);
                    sf=false;
                    p=q;
                }
                else { sf=true; sv=A[p][3]; p=q; }
                continue;
            }

            if (ct==2) {
                out.println(A[p][3]+" "+A[p+1][3]);
                p=q;
                continue;
            }

            boolean tf=false;
            int tv=0;
            int a=p;
            int b=p+1;
            int c=p+2;
            while (ct>2) {
                if (A[a][1]==A[b][1] && A[b][1]==A[c][1]) {
                    out.println(A[a][3]+" "+A[b][3]);
                    ct-=2;
                    a=c;
                    b=a+1;
                    c=b+1;
                }
                else {
                    if (A[b][1]!=A[c][1]) {
                        out.println(A[a][3]+" "+A[b][3]);
                        ct-=2;
                        a=c;
                        b=a+1;
                        c=b+1;
                    }
                    else {
                        out.println(A[b][3]+" "+A[c][3]);
                        ct-=2;
                        if (tf) { out.println(A[tv][3]+" "+A[a][3]); ct--; tf=false; }
                        else { tf=true; tv=a; ct--; }
                        a=c+1;
                        b=a+1;
                        c=b+1;
                    }
                }
            }

            if (ct==2) { out.println(A[a][3]+" "+A[b][3]); }

            if (ct==1) {
                if (tf) { out.println(A[tv][3]+" "+A[a][3]); tf=false; }
                else { tf=true; tv=a; }
            }

            if (tf) {
                if (sf) {
                    out.println(sv+" "+A[tv][3]);
                        sf=false;
                    }
                else { sf=true; sv=A[tv][3]; }
            }

            p=q;
            continue;
        }

        out.flush();
    }

    public static void main(String[] args) throws IOException {
        new Main().solve();
    }
}


import java.io.*;
import java.util.*;

import static java.lang.Math.*;

public class Main {
    class Reader {
        BufferedReader in;

        Reader() {
            in = new BufferedReader(new InputStreamReader(System.in));
        }

        StringTokenizer tok = new StringTokenizer("");

        String next() throws IOException {
            if (!tok.hasMoreTokens()) {
                tok = new StringTokenizer(in.readLine());
            }
            return tok.nextToken();
        }

        int nextInt() throws IOException {
            return Integer.parseInt(next());
        }

        long nextLong() throws IOException {
            return Long.parseLong(next());
        }
    }

    class Writer {
        PrintWriter out;

        Writer() {
            out = new PrintWriter(System.out);
        }

        StringBuilder str = new StringBuilder();

        void print(Object o) {
            str.append(o);
        }

        void close() {
            out.write(str.toString());
            out.close();
        }
    }

    class pair {
        int x, y, z, i;

        pair(int x1, int y1, int z1, int i1) {
            x = x1;
            y = y1;
            z = z1;
            i = i1;
        }
    }

    Writer out;
    ArrayList<pair> a;
    int n;
    boolean used[];

    void printz(int ind) {
        int x1 = a.get(ind).x;
        int y1 = a.get(ind).y;
        pair last = null;
        for (int i = ind; i < n && a.get(i).y == y1 && a.get(i).x == x1; i++) {
            if (last == null) {
                last = a.get(i);
            } else {
                out.print((a.get(i).i + 1) + " " + (last.i + 1) + "\n");
                used[a.get(i).i] = true;
                used[last.i] = true;
                last = null;
            }
        }
    }

    void printy(int ind) {
        int x1 = a.get(ind).x;
        for (int i = ind; i < n && a.get(i).x == x1; i++) {
            printz(i);
            int y1 = a.get(i).y;
            while (i + 1 < n && a.get(i + 1).x == x1 && a.get(i + 1).y == y1)
                i++;
        }
        pair last = null;
        for (int i = ind; i < n && a.get(i).x == x1; i++) {
            if (!used[a.get(i).i]) {
                if (last == null) {
                    last = a.get(i);
                } else {
                    out.print((a.get(i).i + 1) + " " + (last.i + 1) + "\n");
                    used[a.get(i).i] = true;
                    used[last.i] = true;
                    last = null;
                }
            }
        }
    }

    void printx() {
        for (int i = 0; i < n; i++) {
            printy(i);
            int x1 = a.get(i).x;
            while (i + 1 < n && a.get(i + 1).x == x1)
                i++;
        }
        pair last = null;
        for (int i = 0; i < n; i++) {
            if (!used[a.get(i).i]) {
                if (last == null) {
                    last = a.get(i);
                } else {
                    out.print((a.get(i).i + 1) + " " + (last.i + 1) + "\n");
                    used[a.get(i).i] = true;
                    used[last.i] = true;
                    last = null;
                }
            }
        }
    }

    void slave() throws IOException {
        Reader in = new Reader();
        out = new Writer();
        n = in.nextInt();
        a = new ArrayList<>(n);
        used = new boolean[n];
        for (int i = 0; i < n; i++) {
            a.add(new pair(in.nextInt(), in.nextInt(), in.nextInt(), i));
        }
        Collections.sort(a, new Comparator<pair>() {
            @Override
            public int compare(pair o1, pair o2) {
                if (o1.x == o2.x) {
                    if (o1.y == o2.y) {
                        return o1.z - o2.z;
                    } else {
                        return o1.y - o2.y;
                    }
                } else {
                    return o1.x - o2.x;
                }
            }
        });
        printx();
        out.close();
    }

    public static void main(String[] args) throws IOException {
        new Main().slave();
    }
}


import java.io.*;
import java.util.*;

import static java.lang.Math.*;

public class Main {
    class Reader {
        StreamTokenizer tok;

        Reader() {
            tok = new StreamTokenizer(new BufferedInputStream(System.in));
        }

        String next() throws IOException {
            tok.nextToken();
            return tok.sval;
        }

        int nextInt() throws IOException {
            tok.nextToken();
            return (int) (tok.nval);
        }

        long nextLong() throws IOException {
            return Long.parseLong(next());
        }
    }

    class Writer {
        PrintWriter out;

        Writer() {
            out = new PrintWriter(System.out);
        }

        StringBuilder str = new StringBuilder();

        void print(Object o) {
            str.append(o);
        }

        void close() {
            out.write(str.toString());
            out.close();
        }
    }

    class pair {
        int x, y, z, i;

        pair(int x1, int y1, int z1, int i1) {
            x = x1;
            y = y1;
            z = z1;
            i = i1;
        }
    }

    Writer out;
    ArrayList<pair> a;
    int n;
    boolean used[];

    void printz(int ind) {
        int x1 = a.get(ind).x;
        int y1 = a.get(ind).y;
        pair last = null;
        for (int i = ind; i < n && a.get(i).y == y1 && a.get(i).x == x1; i++) {
            if (last == null) {
                last = a.get(i);
            } else {
                out.print((a.get(i).i + 1) + " " + (last.i + 1) + "\n");
                used[a.get(i).i] = true;
                used[last.i] = true;
                last = null;
            }
        }
    }

    void printy(int ind) {
        int x1 = a.get(ind).x;
        for (int i = ind; i < n && a.get(i).x == x1; i++) {
            printz(i);
            int y1 = a.get(i).y;
            while (i + 1 < n && a.get(i + 1).x == x1 && a.get(i + 1).y == y1)
                i++;
        }
        pair last = null;
        for (int i = ind; i < n && a.get(i).x == x1; i++) {
            if (!used[a.get(i).i]) {
                if (last == null) {
                    last = a.get(i);
                } else {
                    out.print((a.get(i).i + 1) + " " + (last.i + 1) + "\n");
                    used[a.get(i).i] = true;
                    used[last.i] = true;
                    last = null;
                }
            }
        }
    }

    void printx() {
        for (int i = 0; i < n; i++) {
            printy(i);
            int x1 = a.get(i).x;
            while (i + 1 < n && a.get(i + 1).x == x1)
                i++;
        }
        pair last = null;
        for (int i = 0; i < n; i++) {
            if (!used[a.get(i).i]) {
                if (last == null) {
                    last = a.get(i);
                } else {
                    out.print((a.get(i).i + 1) + " " + (last.i + 1) + "\n");
                    used[a.get(i).i] = true;
                    used[last.i] = true;
                    last = null;
                }
            }
        }
    }

    void slave() throws IOException {
        Reader in = new Reader();
        out = new Writer();
        n = in.nextInt();
        a = new ArrayList<>(n);
        used = new boolean[n];
        for (int i = 0; i < n; i++) {
            a.add(new pair(in.nextInt(), in.nextInt(), in.nextInt(), i));
        }
        Collections.sort(a, new Comparator<pair>() {
            @Override
            public int compare(pair o1, pair o2) {
                if (o1.x == o2.x) {
                    if (o1.y == o2.y) {
                        return o1.z - o2.z;
                    } else {
                        return o1.y - o2.y;
                    }
                } else {
                    return o1.x - o2.x;
                }
            }
        });
        printx();
        out.close();
    }

    public static void main(String[] args) throws IOException {
        new Main().slave();
    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.StringTokenizer;

public class Remo {

	static FastReader sc = new FastReader();
    static OutputStream outputstream = System.out;
    static PrintWriter out = new PrintWriter(outputstream);

	static class FastReader {
		BufferedReader br;
		StringTokenizer st;

		public FastReader()
		{
			br = new BufferedReader(new
					InputStreamReader(System.in));
		}

		String next()
		{
			while (st == null || !st.hasMoreElements())
			{
				try
				{
					st = new StringTokenizer(br.readLine());
				}
				catch (IOException  e)
				{
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt()
		{
			return Integer.parseInt(next());
		}

		long nextLong()
		{
			return Long.parseLong(next());
		}

		double nextDouble()
		{
			return Double.parseDouble(next());
		}

		String nextLine()
		{
			String str = "";
			try
			{
				str = br.readLine();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
			return str;
		}
	}

	static class Point {
		long x,y,z;
		int ind;

		Point(long x, long y, long z, int ind) {
			this.x=x;
			this.y=y;
			this.z=z;
			this.ind=ind;
		}
		public String toString() {
			return this.x + " " +  this.y + " " + this.z;
		}
	}

	static class comp implements Comparator<Point> {
		public int compare(Point p1, Point p2) {
			if(p1.x==p2.x) {
				if(p1.y==p2.y) {
					if(p1.z>p2.z) return 1;
					return -1;
				} else if(p1.y>p2.y) {
					return 1;
				}
				return -1;
			} else if(p1.x>p2.x) {
				return 1;
			}
			return -1;
		}
	}

	public static void main(String[] args) {

	    int n = sc.nextInt();
	    ArrayList<Point> al = new ArrayList();
	    for(int i = 0; i < n; i++) {
	    	al.add(new Point(sc.nextLong(),sc.nextLong(),sc.nextLong(),i));
	    }
	    Collections.sort(al,new comp());
//	    for(Point p : al) out.println(p);
	    for(int i = 0; i < n; i = i+2) {
	    	out.println((al.get(i).ind+1) + " " + (al.get(i+1).ind+1));
	    }
	    out.close();
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.StringTokenizer;

public class Remo3D {

	static FastReader sc = new FastReader();
    static OutputStream outputstream = System.out;
    static PrintWriter out = new PrintWriter(outputstream);

	static class FastReader {
		BufferedReader br;
		StringTokenizer st;

		public FastReader()
		{
			br = new BufferedReader(new
					InputStreamReader(System.in));
		}

		String next()
		{
			while (st == null || !st.hasMoreElements())
			{
				try
				{
					st = new StringTokenizer(br.readLine());
				}
				catch (IOException  e)
				{
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt()
		{
			return Integer.parseInt(next());
		}

		long nextLong()
		{
			return Long.parseLong(next());
		}

		double nextDouble()
		{
			return Double.parseDouble(next());
		}

		String nextLine()
		{
			String str = "";
			try
			{
				str = br.readLine();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
			return str;
		}
	}

	static class Point {
		long x,y,z;
		int ind;

		Point(long x, long y, long z, int ind) {
			this.x=x;
			this.y=y;
			this.z=z;
			this.ind=ind;
		}
		public String toString() {
			return this.x + " " +  this.y + " " + this.z + " " + (this.ind+1);
		}
	}

	static class comp implements Comparator<Point> {
		public int compare(Point p1, Point p2) {
			if(p1.x==p2.x) {
				if(p1.y==p2.y) {
					if(p1.z>p2.z) return 1;
					return -1;
				} else if(p1.y>p2.y) {
					return 1;
				}
				return -1;
			} else if(p1.x>p2.x) {
				return 1;
			}
			return -1;
		}
	}

	static class Node {
		int x, y;

		Node(int x, int y) {
			this.x=x;
			this.y=y;
		}

		public String toString() {
			return this.x + " " + this.y;
		}
	}

	public static void main(String[] args) {

		int n = sc.nextInt();
		ArrayList<Point> al = new ArrayList();
		for(int i = 0; i < n; i++) {
			al.add(new Point(sc.nextLong(),sc.nextLong(),sc.nextLong(),i));
		}
		Collections.sort(al,new comp());
//		for(Point p : al) out.println(p);
		ArrayList<ArrayList<ArrayList<Integer>>> first = new ArrayList();
		first.add(new ArrayList());
		ArrayList<ArrayList<Integer>> second = first.get(0);
		second.add(new ArrayList());
		ArrayList<Integer> third = second.get(0);
		third.add(al.get(0).ind);
		for(int i = 1; i < n; i++) {
			if(al.get(i-1).x==al.get(i).x) {
				if(al.get(i).y==al.get(i-1).y) {
					third.add(al.get(i).ind);
				} else {
					second.add(new ArrayList());
					third = second.get(second.size()-1);
					third.add(al.get(i).ind);
				}
			} else {
				first.add(new ArrayList());
				second = first.get(first.size()-1);
				second.add(new ArrayList());
				third = second.get(second.size()-1);
				third.add(al.get(i).ind);
			}
		}
//		for(ArrayList<ArrayList<Integer>> sec : first) {
//			for(ArrayList<Integer> fir : sec) out.println(fir.toString());
//			out.println();
//		}
		boolean[] bools = new boolean[n];
		int ind = 0;
		for(int i = 0; i < first.size(); i++) {
			second = first.get(i);
			int firstind = ind;
			int lastind = ind;
			for(int j = 0; j < second.size(); j++) {
				third = second.get(j);
				for(int k = 0; k < third.size()-1; k = k+2) {
//					out.println((third.get(k)+1) + " " + (third.get(k+1)+1));
					out.println((al.get(ind).ind+1) + " " + (al.get(ind+1).ind+1));
					ind = ind+2;
				}
				if(third.size()%2!=0) {
					bools[ind] = true;
					lastind = ind;
					ind++;
				}
			}
			for(int j = firstind; j <= lastind; j++) {
				if(bools[j]) {
					for(int k = j+1; k <= lastind; k++) {
						if(bools[k]) {
							out.println((al.get(j).ind+1) + " " + (al.get(k).ind+1));
						}
						bools[j] = false;
						bools[k] = false;
						j = k;
					}
				}
			}
		}
//		out.println(Arrays.toString(bools));
		for(int i = 0; i < n; i++) {
			if(bools[i]) {
				for(int j = i+1; j < n; j++) {
					if(bools[j]) {
						out.println((al.get(i).ind+1) + " " + (al.get(j).ind+1));
						i=j;
						break;
					}
				}
			}
		}
	    out.close();
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.StringTokenizer;

public class Remo3D {

	static FastReader sc = new FastReader();
    static OutputStream outputstream = System.out;
    static PrintWriter out = new PrintWriter(outputstream);

	static class FastReader {
		BufferedReader br;
		StringTokenizer st;

		public FastReader()
		{
			br = new BufferedReader(new
					InputStreamReader(System.in));
		}

		String next()
		{
			while (st == null || !st.hasMoreElements())
			{
				try
				{
					st = new StringTokenizer(br.readLine());
				}
				catch (IOException  e)
				{
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt()
		{
			return Integer.parseInt(next());
		}

		long nextLong()
		{
			return Long.parseLong(next());
		}

		double nextDouble()
		{
			return Double.parseDouble(next());
		}

		String nextLine()
		{
			String str = "";
			try
			{
				str = br.readLine();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
			return str;
		}
	}

	static class Point {
		long x,y,z;
		int ind;

		Point(long x, long y, long z, int ind) {
			this.x=x;
			this.y=y;
			this.z=z;
			this.ind=ind;
		}
		public String toString() {
			return this.x + " " +  this.y + " " + this.z + " " + (this.ind+1);
		}
	}

	static class comp implements Comparator<Point> {
		public int compare(Point p1, Point p2) {
			if(p1.x==p2.x) {
				if(p1.y==p2.y) {
					if(p1.z>p2.z) return 1;
					return -1;
				} else if(p1.y>p2.y) {
					return 1;
				}
				return -1;
			} else if(p1.x>p2.x) {
				return 1;
			}
			return -1;
		}
	}

	static class Node {
		int x, y;

		Node(int x, int y) {
			this.x=x;
			this.y=y;
		}

		public String toString() {
			return this.x + " " + this.y;
		}
	}

	public static void main(String[] args) {

		int n = sc.nextInt();
		ArrayList<Point> al = new ArrayList();
		for(int i = 0; i < n; i++) {
			al.add(new Point(sc.nextLong(),sc.nextLong(),sc.nextLong(),i));
		}
		Collections.sort(al,new comp());
		ArrayList<ArrayList<ArrayList<Integer>>> first = new ArrayList();
		first.add(new ArrayList());
		ArrayList<ArrayList<Integer>> second = first.get(0);
		second.add(new ArrayList());
		ArrayList<Integer> third = second.get(0);
		third.add(al.get(0).ind);
		for(int i = 1; i < n; i++) {
			if(al.get(i-1).x==al.get(i).x) {
				if(al.get(i).y==al.get(i-1).y) {
					third.add(al.get(i).ind);
				} else {
					second.add(new ArrayList());
					third = second.get(second.size()-1);
					third.add(al.get(i).ind);
				}
			} else {
				first.add(new ArrayList());
				second = first.get(first.size()-1);
				second.add(new ArrayList());
				third = second.get(second.size()-1);
				third.add(al.get(i).ind);
			}
		}
		int ind = 0;
		for(int i = 0; i < first.size(); i++) {
			second = first.get(i);
			for(int j = 0; j < second.size(); j++) {
				third = second.get(j);
				for(int k = 0; k < third.size(); k++) {
					if(ind%2==0) {
						out.print(third.get(k)+1);
					} else {
						out.println(" " + (third.get(k)+1));
					}
					ind++;
				}
			}
		}
	    out.close();
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.StringTokenizer;

public class Remo3D {

	static FastReader sc = new FastReader();
    static OutputStream outputstream = System.out;
    static PrintWriter out = new PrintWriter(outputstream);

	static class FastReader {
		BufferedReader br;
		StringTokenizer st;

		public FastReader()
		{
			br = new BufferedReader(new
					InputStreamReader(System.in));
		}

		String next()
		{
			while (st == null || !st.hasMoreElements())
			{
				try
				{
					st = new StringTokenizer(br.readLine());
				}
				catch (IOException  e)
				{
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt()
		{
			return Integer.parseInt(next());
		}

		long nextLong()
		{
			return Long.parseLong(next());
		}

		double nextDouble()
		{
			return Double.parseDouble(next());
		}

		String nextLine()
		{
			String str = "";
			try
			{
				str = br.readLine();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
			return str;
		}
	}

	static class Point {
		long x,y,z;
		int ind;

		Point(long x, long y, long z, int ind) {
			this.x=x;
			this.y=y;
			this.z=z;
			this.ind=ind;
		}
		public String toString() {
			return this.x + " " +  this.y + " " + this.z + " " + (this.ind+1);
		}
	}

	static class comp implements Comparator<Point> {
		public int compare(Point p1, Point p2) {
			if(p1.x==p2.x) {
				if(p1.y==p2.y) {
					if(p1.z>p2.z) return 1;
					return -1;
				} else if(p1.y>p2.y) {
					return 1;
				}
				return -1;
			} else if(p1.x>p2.x) {
				return 1;
			}
			return -1;
		}
	}

	static class Node {
		int x, y;

		Node(int x, int y) {
			this.x=x;
			this.y=y;
		}

		public String toString() {
			return this.x + " " + this.y;
		}
	}

	public static void main(String[] args) {

		int n = sc.nextInt();
		ArrayList<Point> al = new ArrayList();
		for(int i = 0; i < n; i++) {
			al.add(new Point(sc.nextLong(),sc.nextLong(),sc.nextLong(),i));
		}
		Collections.sort(al,new comp());
//		for(Point p : al) out.println(p);
		ArrayList<ArrayList<ArrayList<Integer>>> first = new ArrayList();
		first.add(new ArrayList());
		ArrayList<ArrayList<Integer>> second = first.get(0);
		second.add(new ArrayList());
		ArrayList<Integer> third = second.get(0);
		third.add(al.get(0).ind);
		for(int i = 1; i < n; i++) {
			if(al.get(i-1).x==al.get(i).x) {
				if(al.get(i).y==al.get(i-1).y) {
					third.add(al.get(i).ind);
				} else {
					second.add(new ArrayList());
					third = second.get(second.size()-1);
					third.add(al.get(i).ind);
				}
			} else {
				first.add(new ArrayList());
				second = first.get(first.size()-1);
				second.add(new ArrayList());
				third = second.get(second.size()-1);
				third.add(al.get(i).ind);
			}
		}
//		for(ArrayList<ArrayList<Integer>> sec : first) {
//			for(ArrayList<Integer> fir : sec) out.println(fir.toString());
//			out.println();
//		}
		boolean[] bools = new boolean[n];
		int ind = 0;
		for(int i = 0; i < first.size(); i++) {
			second = first.get(i);
			int firstind = ind;
			int lastind = ind;
			for(int j = 0; j < second.size(); j++) {
				third = second.get(j);
				for(int k = 0; k < third.size()-1; k = k+2) {
//					out.println((third.get(k)+1) + " " + (third.get(k+1)+1));
					out.println((al.get(ind).ind+1) + " " + (al.get(ind+1).ind+1));
					ind = ind+2;
				}
				if(third.size()%2!=0) {
					bools[ind] = true;
					lastind = ind;
					ind++;
				}
			}
			for(int j = firstind; j <= lastind; j++) {
				if(bools[j]) {
					for(int k = j+1; k <= lastind; k++) {
						if(bools[k]) {
							out.println((al.get(j).ind+1) + " " + (al.get(k).ind+1));
						}
						bools[j] = false;
						bools[k] = false;
						j = k;
						break;
					}
				}
			}
		}
//		out.println(Arrays.toString(bools));
		for(int i = 0; i < n; i++) {
			if(bools[i]) {
				for(int j = i+1; j < n; j++) {
					if(bools[j]) {
						out.println((al.get(i).ind+1) + " " + (al.get(j).ind+1));
						i=j;
						break;
					}
				}
			}
		}
	    out.close();
	}

}