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.FileInputStream;
import java.util.ArrayList;
import java.util.Objects;
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
 */
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);
        C2BalancedRemovalsHarder solver = new C2BalancedRemovalsHarder();
        solver.solve(1, in, out);
        out.close();
    }

    static class C2BalancedRemovalsHarder {
        private int n;
        private int[][] arr;
        private boolean[] flag;
        private static final int D = 3;
        private ArrayList<Util.Pair<Integer>> ans = new ArrayList<>();

        private void function(int from, int to, int dim) {
            if (dim == 1) {
                for (int i = from; i + 1 <= to; i += 2) {
                    ans.add(new Util.Pair<>(arr[i][0], arr[i + 1][0]));
                    flag[arr[i][0]] = flag[arr[i + 1][0]] = true;
                }
                return;
            }
            int num = arr[from][dim];
            int start = from, end = from;
            for (int i = from; i <= to; i++) {
                if (num == arr[i][dim]) end = i;
                else {
                    function(start, end, dim - 1);
                    num = arr[i][dim];
                    start = i;
                    end = i;
                }
            }
            function(start, end, dim - 1);
            ArrayList<Integer> temp = new ArrayList<>();
            for (int i = from; i <= to; i++) {
                if (!flag[arr[i][0]]) temp.add(arr[i][0]);
            }
            for (int i = 0; i + 1 < temp.size(); i += 2) {
                ans.add(new Util.Pair<>(temp.get(i), temp.get(i + 1)));
                flag[temp.get(i)] = flag[temp.get(i + 1)] = true;
            }
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            n = in.nextInt();
            flag = new boolean[n + 1];
            arr = new int[n][D + 1];
            for (int i = 0; i < n; i++) {
                arr[i][0] = i + 1;
                for (int j = 1; j <= D; j++) arr[i][j] = in.nextInt();
            }
            Arrays.sort(arr, new Comparator<int[]>() {

                public int compare(int[] o1, int[] o2) {
                    for (int j = D; j >= 1; j--)
                        if (o1[j] != o2[j]) return o1[j] - o2[j];
                    return 0;
                }
            });
//        for (int i=0; i<arr.length; i++) out.println(Arrays.toString(arr[i]));
            function(0, n - 1, D);
            for (int i = 0; i < ans.size(); i++) {
                out.printsc(ans.get(i).x, ans.get(i).y);
                out.println();
            }
            out.flush();
        }

    }

    static class Util {
        public static class Pair<T> {
            public T x;
            public T y;

            public Pair(T x, T y) {
                this.x = x;
                this.y = y;
            }

            public boolean equals(Object obj) {
                if (!(obj instanceof Util.Pair)) return false;
                Util.Pair<T> pair = (Util.Pair<T>) obj;
                return this.x.equals(pair.x) && this.y.equals(pair.y);
            }

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

            public int hashCode() {
                return Objects.hash(x, y);
            }

        }

    }

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

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

        public InputReader(FileInputStream file) {
            this.stream = file;
        }

        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 nextInt() {
            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 = (res << 3) + (res << 1) + c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        private boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;
        private ArrayList<String> res = new ArrayList<>();
        private StringBuilder sb = new StringBuilder("");

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

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

        public void println(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                sb.append(objects[i]);
            }
            res.add(sb.toString());
            sb = new StringBuilder("");
        }

        public void printsc(Object... objects) {
            for (int i = 0; i < objects.length; i++) {
                sb.append(objects[i]).append(' ');
            }
        }

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

        public void flush() {
            for (String str : res) writer.printf("%s\n", str);
            res.clear();
            sb = new StringBuilder("");
        }

    }
}


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

public class C11237 {

	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);
		PrintWriter pw = new PrintWriter(System.out);
		int n = sc.nextInt();
		PriorityQueue<Point> pq = new PriorityQueue<Point>();
		HashMap<Integer,Integer> xs = new HashMap<Integer, Integer>();
		HashMap<Integer,Integer> ys = new HashMap<Integer, Integer>();
		HashMap<Integer,Integer> zs = new HashMap<Integer, Integer>();
		TreeSet<Integer>tsx = new TreeSet<Integer>();
		TreeSet<Integer>tsy = new TreeSet<Integer>();
		TreeSet<Integer>tsz = new TreeSet<Integer>();
		int [] x = new int [n];
		int [] y = new int [n];
		int [] z = new int [n];
		for(int i=0;i<n;i++) {
			x[i]=sc.nextInt();
			y[i]=sc.nextInt();
			z[i]=sc.nextInt();
			tsx.add(x[i]);
			tsy.add(y[i]);
			tsz.add(z[i]);
		}
		while(!tsx.isEmpty()) {
			xs.put(tsx.pollFirst(), xs.size());
		}
		while(!tsy.isEmpty()) {
			ys.put(tsy.pollFirst(), ys.size());
		}

		while(!tsz.isEmpty()) {
			zs.put(tsz.pollFirst(), zs.size());
		}
		for(int i=0;i<n;i++) {
			pq.add(new Point(i+1, xs.get(x[i]), ys.get(y[i]), zs.get(z[i])));
		}
		while(!pq.isEmpty()) {
//			pw.println(pq);
			Point u = pq.poll();
			Point v = pq.peek();
			if(u.x!=v.x) {
				u.x=v.x;
				u.c++;
				pq.add(u);
			}else if(u.y!=v.y){
				u.y=v.y;
				u.c++;
				pq.add(u);

			}
			else {
				pw.println(u.idx+" "+v.idx);
				pq.poll();
			}
		}
		pw.close();

	}

	static class Point implements Comparable<Point> {
		int idx, x, y, z,c;

		public Point(int i, int x, int y, int z) {
			idx = i;
			this.x = x;
			this.y = y;
			this.z = z;
		}
		public int compareTo(Point p) {
			if(x==p.x) {
				if(y==p.y)
					return z==p.z?c-p.c: z-p.z;
				return y-p.y;
			}
			return x-p.x;
		}
		public String toString () {
			return idx+" "+x+" "+y+" "+z;
		}
	}

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s) {
			br = new BufferedReader(new InputStreamReader(s));
		}

		public Scanner(FileReader r) {
			br = new BufferedReader(r);
		}

		public String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

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

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

		public String nextLine() throws IOException {
			return br.readLine();
		}

		public double nextDouble() throws IOException {
			String x = next();
			StringBuilder sb = new StringBuilder("0");
			double res = 0, f = 1;
			boolean dec = false, neg = false;
			int start = 0;
			if (x.charAt(0) == '-') {
				neg = true;
				start++;
			}
			for (int i = start; i < x.length(); i++)
				if (x.charAt(i) == '.') {
					res = Long.parseLong(sb.toString());
					sb = new StringBuilder("0");
					dec = true;
				} else {
					sb.append(x.charAt(i));
					if (dec)
						f *= 10;
				}
			res += Long.parseLong(sb.toString()) / f;
			return res * (neg ? -1 : 1);
		}

		public boolean ready() throws IOException {
			return br.ready();
		}

	}
}


/**
 * @author derrick20
 */

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

public class BalancedRemovals {
    public static void main(String args[]) throws Exception {
        FastScanner sc = new FastScanner();
        PrintWriter out = new PrintWriter(System.out);

        int N = sc.nextInt();
//        PriorityQueue<Point> pq = new PriorityQueue<>();
        Point[] pts = new Point[N];
        for (int i = 0; i < N; i++) {
            pts[i] = new Point(i + 1, sc.nextInt(), sc.nextInt(), sc.nextInt());
        }
        Arrays.sort(pts);
        int i = 0;
        ArrayList<Point> linesFiltered = new ArrayList<>();
        while (i < N) {
            if (i < N - 1 && pts[i].x == pts[i + 1].x && pts[i].y == pts[i + 1].y) {
                out.println(pts[i].idx + " " + pts[i + 1].idx);
                i += 2;
            }
            else {
                linesFiltered.add(pts[i]);
                i++;
            }
        }
        i = 0;
        ArrayList<Point> planesFiltered = new ArrayList<>();
        while (i < linesFiltered.size()) {
            // After this, there will be no x groups
            if (i < linesFiltered.size() - 1 && linesFiltered.get(i).x == linesFiltered.get(i + 1).x) {
                out.println(linesFiltered.get(i).idx + " " + linesFiltered.get(i + 1).idx);
                i += 2;
            }
            else {
                planesFiltered.add(linesFiltered.get(i));
                i++;
            }
        }
        i = 0;
        while (i < planesFiltered.size()) {
            // After this, there will be no x groups
            out.println(planesFiltered.get(i).idx + " " + planesFiltered.get(i + 1).idx);
            i += 2;
        }

        out.close();
    }

    static class Point implements Comparable<Point> {
        int idx, x, y, z;
        public Point(int index, int myX, int myY, int myZ) {
            idx = index; x = myX; y = myY; z = myZ;
        }
        public String toString() {
            return "(" + x + ", " + y + ", " + y + ")";
        }
        public int compareTo(Point p2) {
            if (x != p2.x) return x - p2.x;
            else if (y != p2.y) return y - p2.y;
            else return z - p2.z;
        }
        public int getX() {
            return x;
        }
        public int getY() {
            return y;
        }
        public int getZ() {
            return z;
        }
    }

    static class FastScanner {
        public int BS = 1<<16;
        public char NC = (char)0;
        byte[] buf = new byte[BS];
        int bId = 0, size = 0;
        char c = NC;
        double cnt = 1;
        BufferedInputStream in;

        public FastScanner() {
            in = new BufferedInputStream(System.in, BS);
        }

        public FastScanner(String s) {
            try {
                in = new BufferedInputStream(new FileInputStream(new File(s)), BS);
            }
            catch (Exception e) {
                in = new BufferedInputStream(System.in, BS);
            }
        }

        private char getChar(){
            while(bId==size) {
                try {
                    size = in.read(buf);
                }catch(Exception e) {
                    return NC;
                }
                if(size==-1)return NC;
                bId=0;
            }
            return (char)buf[bId++];
        }

        public int nextInt() {
            return (int)nextLong();
        }

        public long nextLong() {
            cnt=1;
            boolean neg = false;
            if(c==NC)c=getChar();
            for(;(c<'0' || c>'9'); c = getChar()) {
                if(c=='-')neg=true;
            }
            long res = 0;
            for(; c>='0' && c <='9'; c=getChar()) {
                res = (res<<3)+(res<<1)+c-'0';
                cnt*=10;
            }
            return neg?-res:res;
        }

        public double nextDouble() {
            double cur = nextLong();
            return c!='.' ? cur:cur+nextLong()/cnt;
        }

        public String next() {
            StringBuilder res = new StringBuilder();
            while(c<=32)c=getChar();
            while(c>32) {
                res.append(c);
                c=getChar();
            }
            return res.toString();
        }

        public String nextLine() {
            StringBuilder res = new StringBuilder();
            while(c<=32)c=getChar();
            while(c!='\n') {
                res.append(c);
                c=getChar();
            }
            return res.toString();
        }

        public boolean hasNext() {
            if(c>32)return true;
            while(true) {
                c=getChar();
                if(c==NC)return false;
                else if(c>32)return true;
            }
        }
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;

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

    static class C2SbalansirovannieUdaleniyaPoslozhnee {
        PrintWriter out;

        void solve1d(P[] p, int a, int b) {
            int prev = -1;
            for (int i = a; i < b; i++) {
                if (!p[i].killed) {
                    if (prev != -1) {
                        out.println(p[prev].id + " " + p[i].id);
                        p[prev].killed = true;
                        p[i].killed = true;
                        prev = -1;
                    } else {
                        prev = i;
                    }
                }
            }
        }

        void solve2d(P[] p, int a, int b) {
            int s = a;
            int t = a + 1;
            while (s < b) {
                while (t < b && p[t].y == p[s].y) {
                    t++;
                }
                solve1d(p, s, t);
                s = t;
            }
            solve1d(p, a, b);
        }

        public void solve(int testNumber, Scanner in, PrintWriter out) {
            this.out = out;
            int n = in.nextInt();
            P[] p = new P[n];
            for (int i = 0; i < n; i++) {
                p[i] = new P(i + 1, in.nextInt(), in.nextInt(), in.nextInt());
            }

            Arrays.sort(p);
            int s = 0;
            int f = 1;
            while (s < n) {
                while (f < n && p[f].x == p[s].x) {
                    f++;
                }
                solve2d(p, s, f);
                s = f;
            }
            solve1d(p, 0, n);
        }

        class P implements Comparable<P> {
            int id;
            int x;
            int y;
            int z;
            boolean killed;

            public P(int id, int x, int y, int z) {
                this.id = id;
                this.x = x;
                this.y = y;
                this.z = z;
                killed = false;
            }

            public int compareTo(P o) {
                if (x != o.x) return Integer.compare(x, o.x);
                if (y != o.y) return Integer.compare(y, o.y);
                if (z != o.z) return Integer.compare(z, o.z);
                return id - o.id;
            }

        }

    }
}


// practice with rainboy
import java.io.*;
import java.util.*;

public class CF1237C2 extends PrintWriter {
	CF1237C2() { super(System.out); }
	Scanner sc = new Scanner(System.in);
	public static void main(String[] $) {
		CF1237C2 o = new CF1237C2(); o.main(); o.flush();
	}

	static class V {
		int i, x, y, z;
		boolean used;
		V(int i, int x, int y, int z) {
			this.i = i; this.x = x; this.y = y; this.z = z;
		}
	}
	void pairup(V[] vv, int l, int r) {
		for (int i = -1, j = l; j < r; j++)
			if (!vv[j].used) {
				if (i == -1)
					i = j;
				else {
					vv[i].used = vv[j].used = true;
					println((vv[i].i + 1) + " " + (vv[j].i + 1));
					i = -1;
				}
			}
	}
	void solve_y(V[] vv, int l, int r) {
		for (int i = l, j; i < r; i = j) {
			j = i + 1;
			while (j < r && vv[j].y == vv[i].y)
				j++;
			pairup(vv, i, j);
		}
		pairup(vv, l, r);
	}
	void solve_z(V[] vv, int l, int r) {
		for (int i = l, j; i < r; i = j) {
			j = i + 1;
			while (j < r && vv[j].z == vv[i].z)
				j++;
			solve_y(vv, i, j);
		}
		pairup(vv, l, r);
	}
	void main() {
		int n = sc.nextInt();
		V[] vv = new V[n];
		for (int i = 0; i < n; i++) {
			int x = sc.nextInt();
			int y = sc.nextInt();
			int z = sc.nextInt();
			vv[i] = new V(i, x, y, z);
		}
		Arrays.sort(vv, (u, v) -> u.z != v.z ? u.z - v.z : u.y != v.y ? u.y - v.y : u.x - v.x);
		solve_z(vv, 0, n);
	}
}


// practice with rainboy
import java.io.*;
import java.util.*;

public class CF1237C2 extends PrintWriter {
	CF1237C2() { super(System.out); }
	Scanner sc = new Scanner(System.in);
	public static void main(String[] $) {
		CF1237C2 o = new CF1237C2(); o.main(); o.flush();
	}

	static class V {
		int i, x, y, z;
		boolean used;
		V(int i, int x, int y, int z) {
			this.i = i; this.x = x; this.y = y; this.z = z;
		}
	}
	void pairup(V[] vv, int l, int r) {
		for (int i = -1, j = l; j < r; j++)
			if (!vv[j].used) {
				if (i == -1)
					i = j;
				else {
					vv[i].used = vv[j].used = true;
					println((vv[i].i + 1) + " " + (vv[j].i + 1));
					i = -1;
				}
			}
	}
	void solve_x(V[] vv, int l, int r) {
		for (int i = l, j; i < r; i = j) {
			j = i + 1;
			while (j < r && vv[j].x == vv[i].x)
				j++;
			pairup(vv, i, j);
		}
	}
	void solve_y(V[] vv, int l, int r) {
		for (int i = l, j; i < r; i = j) {
			j = i + 1;
			while (j < r && vv[j].y == vv[i].y)
				j++;
			solve_x(vv, i, j);
		}
		pairup(vv, l, r);
	}
	void solve_z(V[] vv, int l, int r) {
		for (int i = l, j; i < r; i = j) {
			j = i + 1;
			while (j < r && vv[j].z == vv[i].z)
				j++;
			solve_y(vv, i, j);
		}
		pairup(vv, l, r);
	}
	void main() {
		int n = sc.nextInt();
		V[] vv = new V[n];
		for (int i = 0; i < n; i++) {
			int x = sc.nextInt();
			int y = sc.nextInt();
			int z = sc.nextInt();
			vv[i] = new V(i, x, y, z);
		}
		Arrays.sort(vv, (u, v) -> u.z != v.z ? u.z - v.z : u.y != v.y ? u.y - v.y : u.x - v.x);
		solve_z(vv, 0, n);
	}
}


import java.util.Scanner;
import java.util.Stack;
import java.util.ArrayList;
import java.util.Arrays;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int n = s.nextInt();
	     int[][] arr = new int[n][4];
	     StringBuffer strbf = new StringBuffer();
	     for(int i = 0; i < n; i++) {
	         arr[i][0] = s.nextInt();
	         arr[i][1] = s.nextInt();
	         arr[i][2] = s.nextInt();
	         arr[i][3] = i + 1;
	     }
	     Stack<Integer> stack = new Stack<Integer>();
	     Arrays.sort(arr, ((A, B) -> (A[0] == B[0]) ? (A[1] == B[1] ? A[2] - B[2] : A[1] - B[1]) : A[0] - B[0]));
	     boolean done[] = new boolean[n];
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.peek();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1] && arr[i][2] == arr[p][2]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         stack.pop();
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     stack.clear();
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.peek();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         stack.pop();
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     stack.clear();
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.peek();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         stack.pop();
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     int count = 0;
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               strbf.append(arr[i][3] + " ");
	               count ^= 1;
	               if(count == 0) {
     	               strbf.append(System.lineSeparator());
	               }
	          }

	     }
	     System.out.println(strbf.toString());
	}

}


import java.util.Scanner;
import java.util.Stack;
import java.util.ArrayList;
import java.util.Arrays;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int n = s.nextInt();
	     int[][] arr = new int[n][4];
	     StringBuffer strbf = new StringBuffer();
	     for(int i = 0; i < n; i++) {
	         arr[i][0] = s.nextInt();
	         arr[i][1] = s.nextInt();
	         arr[i][2] = s.nextInt();
	         arr[i][3] = i + 1;
	     }
	     Stack<Integer> stack = new Stack<Integer>();
	     Arrays.sort(arr, ((A, B) -> (A[0] == B[0]) ? (A[1] == B[1] ? A[2] - B[2] : A[1] - B[1]) : A[0] - B[0]));
	     boolean done[] = new boolean[n];
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.peek();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1] && arr[i][2] == arr[p][2]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         stack.pop();
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     stack.clear();
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.peek();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         stack.pop();
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.peek();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         stack.pop();
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     int count = 0;
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               strbf.append(arr[i][3] + " ");
	               count ^= 1;
	               if(count == 0) {
     	               strbf.append(System.lineSeparator());
	               }
	          }

	     }
	     System.out.println(strbf.toString());
	}

}


import java.util.Scanner;
import java.util.Stack;
import java.util.ArrayList;
import java.util.Arrays;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int n = s.nextInt();
	     int[][] arr = new int[n][4];
	     StringBuffer strbf = new StringBuffer();
	     for(int i = 0; i < n; i++) {
	         arr[i][0] = s.nextInt();
	         arr[i][1] = s.nextInt();
	         arr[i][2] = s.nextInt();
	         arr[i][3] = i + 1;
	     }
	     Stack<Integer> stack = new Stack<Integer>();
	     Arrays.sort(arr, ((A, B) -> (A[0] == B[0]) ? (A[1] == B[1] ? A[2] - B[2] : A[1] - B[1]) : A[0] - B[0]));
	     boolean done[] = new boolean[n];
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.pop();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1] && arr[i][2] == arr[p][2]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     stack.clear();
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.pop();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.pop();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     int count = 0;
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               strbf.append(arr[i][3] + " ");
	               count ^= 1;
	               if(count == 0) {
     	               strbf.append(System.lineSeparator());
	               }
	          }

	     }
	     System.out.println(strbf.toString());
	}

}


import java.util.Scanner;
import java.util.Stack;
import java.util.ArrayList;
import java.util.Arrays;

public class Main {

	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int n = s.nextInt();
	     int[][] arr = new int[n][4];
	     StringBuffer strbf = new StringBuffer();
	     for(int i = 0; i < n; i++) {
	         arr[i][0] = s.nextInt();
	         arr[i][1] = s.nextInt();
	         arr[i][2] = s.nextInt();
	         arr[i][3] = i + 1;
	     }
	     Stack<Integer> stack = new Stack<Integer>();
	     Arrays.sort(arr, ((A, B) -> (A[0] == B[0]) ? (A[1] == B[1] ? A[2] - B[2] : A[1] - B[1]) : A[0] - B[0]));
	     boolean done[] = new boolean[n];
	    /* for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.peek();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1] && arr[i][2] == arr[p][2]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         stack.pop();
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     stack.clear();*/
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.peek();
	                    if(arr[i][0] == arr[p][0] && arr[i][1] == arr[p][1]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         stack.pop();
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     stack = new Stack<Integer>();
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               if(!stack.isEmpty()) {
	                    int p = stack.peek();
	                    if(arr[i][0] == arr[p][0]) {
	                         strbf.append(arr[p][3] + " " + arr[i][3] + System.lineSeparator());
	                         done[i] = done[p] = true;
	                         stack.pop();
	                         continue;
	                    }
	               }
	               stack.push(i);
	          }
	     }
	     int count = 0;
	     for(int i = 0; i < n; i++) {
	          if(!done[i]) {
	               strbf.append(arr[i][3] + " ");
	               count ^= 1;
	               if(count == 0) {
     	               strbf.append(System.lineSeparator());
	               }
	          }

	     }
	     System.out.println(strbf.toString());
	}

}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
/*
4 3
1 2
5 7
8 6

 */
public class C {

	static ArrayList<Integer> res;
	public static void main(String[] args) {
		FS in = new FS();
		PrintWriter out = new PrintWriter(System.out);
		int N = in.nextInt();
		Vec ar[] = new Vec[N];
		for(int i = 0; i < N; i++)
			ar[i] = new Vec(in.nextLong(),in.nextLong(),in.nextLong(),i);
		Arrays.sort(ar, (a,b) -> Long.compare(a.z, b.z));
		res = new ArrayList<Integer>();

		int l = 0, r = 0;
		Vec prev = null;
		while(l < N) {
			while(r < N-1 && ar[r+1].z == ar[l].z) r++;
			TreeSet<Vec> ts = new TreeSet<Vec>();
			for(int i = l; i <= r; i++) ts.add(ar[i]);
			if(prev != null) { //find closest and pair
				long best = Long.MAX_VALUE;
				Vec use = null;
				for(Vec v : ts) {
					if(v.man(prev) < best) {
						best = v.man(prev);
						use = v;
					}
				}
				ts.remove(use);
				res.add(use.id); res.add(prev.id);
			}
			prev = solve(ts);
			l = r+1;
			r = l;
		}

		for(int i = 0; i < N; i += 2)
			out.println(res.get(i)+" "+res.get(i+1));
		out.close();
	}

	static Vec solve(TreeSet<Vec> vs) {
		if(vs.size() == 0) return null;
		if(vs.size() == 1) return vs.first();

		TreeMap<Long, TreeSet<Vec>> map = new TreeMap<>();
		for(Vec v : vs) {
			if(!map.containsKey(v.x)) {
				map.put(v.x, new TreeSet<Vec>());
			}
			map.get(v.x).add(v);
		}

		for(long ll : map.keySet()) {
			TreeSet<Vec> ts = map.get(ll);
			while(ts.size() > 1) {
				Vec a = ts.pollFirst();
				Vec b = ts.pollFirst();
				res.add(a.id); res.add(b.id);
			}
			if(ts.size() == 1) {
				if(map.higherKey(ll) == null) return ts.first();
				Vec a = ts.pollFirst();
				long l2 = map.higherKey(ll);
				Vec p1 = map.get(l2).ceiling(a);
				Vec p2 = map.get(l2).floor(a);
				Vec use = null;
				if(p1 != null && p2 != null)
					use = Math.abs(p1.y-a.y) < Math.abs(p2.y-a.y) ? p1 : p2;
				else if(p1 != null) use = p1;
				else use = p2;

				res.add(a.id); res.add(use.id);
				map.get(l2).remove(use);
			}
		}
		return null;
	}

	static class Vec implements Comparable<Vec>{
		long x,y,z;
		int id;
		public Vec(long xx, long yy, long zz, int ii) {
			x=xx;
			y=yy;
			z=zz;
			id=ii+1;
		}
		@Override
		public int compareTo(Vec o) {
			if(y == o.y) return id-o.id;
			return Long.compare(y, o.y);
		}
		public long man(Vec o) {
			return Math.abs(x-o.x) + Math.abs(y-o.y);
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		public String next() {
			while(st == null || !st.hasMoreElements()) {
				try { st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
		double nextDouble() {
			return Double.parseDouble(next());
		}
		long nextLong() {
			return Long.parseLong(next());
		}
	}
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class C {

	public static void main(String[] args) {
		FS in = new FS();
		PrintWriter out = new PrintWriter(System.out);
		int N = in.nextInt();
		Vec ar[] = new Vec[N];
		for(int i = 0; i < N; i++)
			ar[i] = new Vec(in.nextLong(),in.nextLong(),in.nextLong(),i);
		Arrays.sort(ar);
		ArrayList<Integer> res = new ArrayList<Integer>();

		boolean used[] = new boolean[N];
		int l = 0, r = 0;
		Vec prev = null;
		while(l < N) {
			while(r < N-1 && ar[r+1].z == ar[l].z) r++;
			TreeSet<Vec> ts = new TreeSet<Vec>();
			for(int i = l; i <= r; i++) ts.add(ar[i]);
			if(prev != null) { //find closest and pair
				long best = Long.MAX_VALUE;
				Vec use = null;
				for(Vec v : ts) {
					if(v.man(prev) < best) {
						best = v.man(prev);
						use = v;
					}
				}
				ts.remove(use);
				res.add(use.id); res.add(prev.id);
			}
			while(ts.size() > 1) {
				Vec a = ts.pollFirst();
				Vec b = ts.pollFirst();
				res.add(a.id); res.add(b.id);
			}
			prev = ts.size() == 0 ? null : ts.first();
			l = r+1;
			r = l;
		}

		for(int i = 0; i < N; i += 2)
			out.println(res.get(i)+" "+res.get(i+1));
		out.close();
	}

	static class Vec implements Comparable<Vec>{
		long x,y,z;
		int id;
		public Vec(long xx, long yy, long zz, int ii) {
			x=xx;
			y=yy;
			z=zz;
			id=ii+1;
		}
		@Override
		public int compareTo(Vec o) {
			if(z != o.z) return Long.compare(z, o.z);
			if(x != o.x) return Long.compare(x, o.x);
			return Long.compare(y, o.y);
		}
		public long man(Vec o) {
			return Math.abs(x-o.x) + Math.abs(y-o.y);
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		public String next() {
			while(st == null || !st.hasMoreElements()) {
				try { st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
		double nextDouble() {
			return Double.parseDouble(next());
		}
		long nextLong() {
			return Long.parseLong(next());
		}
	}
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

public class C {

	public static void main(String[] args) {
		FS in = new FS();
		PrintWriter out = new PrintWriter(System.out);
		int N = in.nextInt();
		Vec ar[] = new Vec[N];
		for(int i = 0; i < N; i++)
			ar[i] = new Vec(in.nextLong(),in.nextLong(),in.nextLong(),i);
		Arrays.sort(ar);
		for(int i = 0; i < N; i += 2) {
			out.println(ar[i].id+" "+ar[i+1].id);
		}
		out.close();
	}

	static class Vec implements Comparable<Vec>{
		long x,y,z,id;
		public Vec(long xx, long yy, long zz, int ii) {
			x=xx;
			y=yy;
			z=zz;
			id=ii+1;
		}
		@Override
		public int compareTo(Vec o) {
			if(z != o.z) return Long.compare(z, o.z);
			if(x != o.x) return Long.compare(x, o.x);
			return Long.compare(y, o.y);
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		public String next() {
			while(st == null || !st.hasMoreElements()) {
				try { st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
		double nextDouble() {
			return Double.parseDouble(next());
		}
		long nextLong() {
			return Long.parseLong(next());
		}
	}
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

public class C {

	static ArrayList<Integer> res;
	public static void main(String[] args) {
		FS in = new FS();
		PrintWriter out = new PrintWriter(System.out);
		int N = in.nextInt();
		Vec ar[] = new Vec[N];
		for(int i = 0; i < N; i++)
			ar[i] = new Vec(in.nextLong(),in.nextLong(),in.nextLong(),i);
		Arrays.sort(ar);
		res = new ArrayList<Integer>();

		int l = 0, r = 0;
		Vec prev = null;
		while(l < N) {
			while(r < N-1 && ar[r+1].z == ar[l].z) r++;
			TreeSet<Vec> ts = new TreeSet<Vec>();
			for(int i = l; i <= r; i++) ts.add(ar[i]);
			if(prev != null) { //find closest and pair
				long best = Long.MAX_VALUE;
				Vec use = null;
				for(Vec v : ts) {
					if(v.man(prev) < best) {
						best = v.man(prev);
						use = v;
					}
				}
				ts.remove(use);
				res.add(use.id); res.add(prev.id);
			}
			prev = solve(ts);
			l = r+1;
			r = l;
		}

		for(int i = 0; i < N; i += 2)
			out.println(res.get(i)+" "+res.get(i+1));
		out.close();
	}

	static Vec solve(TreeSet<Vec> vs) {
		if(vs.size() == 0) return null;
		if(vs.size() == 1) return vs.first();

		TreeMap<Long, TreeSet<Vec>> map = new TreeMap<>();
		for(Vec v : vs) {
			if(!map.containsKey(v.x)) {
				map.put(v.x, new TreeSet<Vec>());
			}
			map.get(v.x).add(v);
		}

		for(long ll : map.keySet()) {
			TreeSet<Vec> ts = map.get(ll);
			while(ts.size() > 1) {
				Vec a = ts.pollFirst();
				Vec b = ts.pollFirst();
				res.add(a.id); res.add(b.id);
			}
			if(ts.size() == 1) {
				if(map.higherKey(ll) == null) return ts.first();
				Vec a = ts.pollFirst();
				long l2 = map.higherKey(ll);
				Vec p1 = map.get(l2).ceiling(a);
				Vec p2 = map.get(l2).floor(a);
				if(p1 != null) {
					res.add(a.id); res.add(p1.id);
					map.get(l2).remove(p1);
				}
				else if(p2 != null) {
					res.add(a.id); res.add(p2.id);
					map.get(l2).remove(p2);
				}
			}
		}
		return null;
	}

	static class Vec implements Comparable<Vec>{
		long x,y,z;
		int id;
		public Vec(long xx, long yy, long zz, int ii) {
			x=xx;
			y=yy;
			z=zz;
			id=ii+1;
		}
		@Override
		public int compareTo(Vec o) {
			if(y == o.y) return id-o.id;
			return Long.compare(y, o.y);
		}
		public long man(Vec o) {
			return Math.abs(x-o.x) + Math.abs(y-o.y);
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		public String next() {
			while(st == null || !st.hasMoreElements()) {
				try { st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
		double nextDouble() {
			return Double.parseDouble(next());
		}
		long nextLong() {
			return Long.parseLong(next());
		}
	}
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
/*
4 3
1 2
5 7
8 6

 */
public class C {

	static ArrayList<Integer> res;
	public static void main(String[] args) {
		FS in = new FS();
		PrintWriter out = new PrintWriter(System.out);
		int N = in.nextInt();
		Vec ar[] = new Vec[N];
		for(int i = 0; i < N; i++)
			ar[i] = new Vec(in.nextLong(),in.nextLong(),in.nextLong(),i);
		Arrays.sort(ar, (a,b) -> Long.compare(a.z, b.z));
		res = new ArrayList<Integer>();

		int l = 0, r = 0;
		Vec prev = null;
		while(l < N) {
			while(r < N-1 && ar[r+1].z == ar[l].z) r++;
			TreeSet<Vec> ts = new TreeSet<Vec>();
			for(int i = l; i <= r; i++) ts.add(ar[i]);
			if(prev != null) { //find closest and pair
				long best = Long.MAX_VALUE;
				Vec use = null;
				for(Vec v : ts) {
					if(v.man(prev) < best) {
						best = v.man(prev);
						use = v;
					}
				}
				ts.remove(use);
				res.add(use.id); res.add(prev.id);
			}
			prev = solve(ts);
			l = r+1;
			r = l;
		}

		for(int i = 0; i < N; i += 2)
			out.println(res.get(i)+" "+res.get(i+1));
		out.close();
	}

	static Vec solve(TreeSet<Vec> vs) {
		if(vs.size() == 0) return null;
		if(vs.size() == 1) return vs.first();

		TreeMap<Long, TreeSet<Vec>> map = new TreeMap<>();
		for(Vec v : vs) {
			if(!map.containsKey(v.x)) {
				map.put(v.x, new TreeSet<Vec>());
			}
			map.get(v.x).add(v);
		}

		for(long ll : map.keySet()) {
			TreeSet<Vec> ts = map.get(ll);
			while(ts.size() > 1) {
				Vec a = ts.pollFirst();
				Vec b = ts.pollFirst();
				res.add(a.id); res.add(b.id);
			}
			if(ts.size() == 1) {
				if(map.higherKey(ll) == null) return ts.first();
				Vec a = ts.pollFirst();
				long l2 = map.higherKey(ll);
				Vec p1 = map.get(l2).ceiling(a);
				Vec p2 = map.get(l2).floor(a);
				if(p1 != null) {
					res.add(a.id); res.add(p1.id);
					map.get(l2).remove(p1);
				}
				else if(p2 != null) {
					res.add(a.id); res.add(p2.id);
					map.get(l2).remove(p2);
				}
			}
		}
		return null;
	}

	static class Vec implements Comparable<Vec>{
		long x,y,z;
		int id;
		public Vec(long xx, long yy, long zz, int ii) {
			x=xx;
			y=yy;
			z=zz;
			id=ii+1;
		}
		@Override
		public int compareTo(Vec o) {
			if(y == o.y) return id-o.id;
			return Long.compare(y, o.y);
		}
		public long man(Vec o) {
			return Math.abs(x-o.x) + Math.abs(y-o.y);
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		public String next() {
			while(st == null || !st.hasMoreElements()) {
				try { st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() {
			return Integer.parseInt(next());
		}
		double nextDouble() {
			return Double.parseDouble(next());
		}
		long nextLong() {
			return Long.parseLong(next());
		}
	}
}


// package Quarantine;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class BalancedRemovals {
    public static void main(String[] args)throws IOException {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        int n=Integer.parseInt(br.readLine());
        ArrayList<CoPints> points=new ArrayList<>();
        StringTokenizer st;
        for(int i=1;i<=n;i++){
            st=new StringTokenizer(br.readLine());
            long x=Long.parseLong(st.nextToken());
            long y=Long.parseLong(st.nextToken());
            long z=Long.parseLong(st.nextToken());
            points.add(new CoPints(x,y,z,i));
        }
        Collections.sort(points,new SortByX());
        int x_ind=0;
        int i=n/2;
        StringBuilder print=new StringBuilder();
        ArrayList<CoPints> residual=new ArrayList<>();
        while (x_ind<n){
            long x=points.get(x_ind).x;
            ArrayList<CoPints> yz=new ArrayList<>();
            while(x_ind<n&&points.get(x_ind).x==x){
                yz.add(points.get(x_ind));
                x_ind++;
            }
            Collections.sort(yz,new SortByY());
            int y_index=0;
            ArrayList<CoPints> residualyz=new ArrayList<>();
            while(y_index<yz.size()){
                ArrayList<CoPints> z=new ArrayList<>();
                long y=yz.get(y_index).y;
                while (y_index<yz.size()&&yz.get(y_index).y==y){
                    z.add(yz.get(y_index));
                    y_index++;
                }
                Collections.sort(z,new SortByZ());
                int k=0;
                while(k+1<z.size()){
                    print.append(z.get(k).index+" "+z.get(k+1).index+"\n");
                    k+=2;
                }
                if(k==z.size()-1){
                    residualyz.add(z.get(k));
                }
//                System.out.println(y_index);
            }
            Collections.sort(residualyz,new SortByY());
            int k=0;
            while(k+1<residualyz.size()){
                print.append(residualyz.get(k).index+" "+residualyz.get(k+1).index+"\n");
                k+=2;
            }
            if(k==residualyz.size()-1){
                residual.add(residualyz.get(k));
            }
//            System.out.println(x_ind);
        }
        Collections.sort(residual,new SortByX());
        for(int k=0;k<residual.size()/2;k++){
            print.append(residual.get(2*k).index+" "+residual.get(2*k+1).index+"\n");
        }
        System.out.println(print.toString());
    }
}

class SortByX implements Comparator<CoPints>{
    @Override
    public int compare(CoPints o1, CoPints o2) {
        return Long.compare(o1.x,o2.x);
    }
}

class SortByY implements Comparator<CoPints>{
    @Override
    public int compare(CoPints o1, CoPints o2) {
        return Long.compare(o1.y,o2.y);

    }
}

class SortByZ implements Comparator<CoPints>{
    @Override
    public int compare(CoPints o1, CoPints o2) {
        return Long.compare(o1.z,o2.z);
    }
}

class CoPints{
    long x,y,z;
    int index;
    public CoPints(long x,long y,long z,int index){
        this.x=x;
        this.y=y;
        this.z=z;
        this.index=index;
    }
    @Override
    public String toString() {
        return this.index+"";
    }
}


// package Quarantine;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class BalancedRemovals {
    public static void main(String[] args)throws IOException {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        int n=Integer.parseInt(br.readLine());
        TreeSet<CoPints> points=new TreeSet<>();
        StringTokenizer st;
        for(int i=1;i<=n;i++){
            st=new StringTokenizer(br.readLine());
            long x=Long.parseLong(st.nextToken());
            long y=Long.parseLong(st.nextToken());
            long z=Long.parseLong(st.nextToken());
            points.add(new CoPints(x,y,z,i));
        }
        StringBuilder print=new StringBuilder();
        for(int i=1;i<=n/2;i++){
//            System.out.println(points.toString());
            CoPints first=points.pollFirst();
            CoPints ahead=points.pollFirst();
            print.append(first.index+" "+ahead.index+"\n");
        }
        System.out.print(print.toString());
    }
}

class CoPints implements Comparable<CoPints>{
    long x,y,z;
    int index;
    public CoPints(long x,long y,long z,int index){
        this.x=x;
        this.y=y;
        this.z=z;
        this.index=index;
    }

    @Override
    public int compareTo(CoPints o) {
        if(this.index==o.index){
            return 0;
        }
        if(this.x<o.x){
            return -1;
        }
        else if(this.x>o.x){
            return 1;
        }
        else{
            if(this.y<o.y){
                return -1;
            }
            else if(this.y>o.y){
                return 1;
            }
            else{
                if(this.z<o.z){
                    return -1;
                }
                else{
                    return 1;
                }
            }
        }
    }

    @Override
    public String toString() {
        return this.index+"";
    }
}


// package Quarantine;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class BalancedRemovals {
    public static void main(String[] args)throws IOException {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        int n=Integer.parseInt(br.readLine());
        ArrayList<CoPints> points=new ArrayList<>();
        StringTokenizer st;
        for(int i=1;i<=n;i++){
            st=new StringTokenizer(br.readLine());
            long x=Long.parseLong(st.nextToken());
            long y=Long.parseLong(st.nextToken());
            long z=Long.parseLong(st.nextToken());
            points.add(new CoPints(x,y,z,i));
        }
        Collections.sort(points,new SortByX());
        int x_ind=0;
        int i=n/2;
        StringBuilder print=new StringBuilder();
        ArrayList<CoPints> residual=new ArrayList<>();
        while (x_ind<n){
            long x=points.get(x_ind).x;
            ArrayList<CoPints> yz=new ArrayList<>();
            while(x_ind<n&&points.get(x_ind).x==x){
                yz.add(points.get(x_ind));
                x_ind++;
            }
            Collections.sort(yz,new SortByY());
            int y_index=0;
            ArrayList<CoPints> residualyz=new ArrayList<>();
            while(y_index<yz.size()){
                ArrayList<CoPints> z=new ArrayList<>();
                long y=yz.get(y_index).y;
                while (y_index<yz.size()&&yz.get(y_index).y==y){
                    z.add(yz.get(y_index));
                    y_index++;
                }
                Collections.sort(z,new SortByZ());
                int k=0;
                while(k+1<z.size()){
                    print.append(z.get(k).index+" "+z.get(k+1).index+"\n");
                    k+=2;
                }
                if(k==z.size()-1){
                    residualyz.add(z.get(k));
                }
//                System.out.println(y_index);
            }
            Collections.sort(residualyz,new SortByY());
            int k=0;
            while(k+1<residualyz.size()){
                print.append(residualyz.get(k).index+" "+residualyz.get(k+1).index+"\n");
                k+=2;
            }
            if(k==residualyz.size()-1){
                residual.add(residualyz.get(k));
            }
//            System.out.println(x_ind);
        }
        Collections.sort(residual,new SortByX());
        for(int k=0;k<residual.size()/2;k++){
            print.append(residual.get(2*k).index+" "+residual.get(2*k+1).index+"\n");
        }
        System.out.println(print.toString());
    }
}

class SortByX implements Comparator<CoPints>{
    @Override
    public int compare(CoPints o1, CoPints o2) {
        if(o1.x<o2.x){
            return -1;
        }
        else{
            return 1;
        }
    }
}

class SortByY implements Comparator<CoPints>{
    @Override
    public int compare(CoPints o1, CoPints o2) {
        if(o1.y<o2.y){
            return -1;
        }
        else{
            return 1;
        }
    }
}

class SortByZ implements Comparator<CoPints>{
    @Override
    public int compare(CoPints o1, CoPints o2) {
        if(o1.z<o2.z){
            return -1;
        }
        else{
            return 1;
        }
    }
}

class CoPints{
    long x,y,z;
    int index;
    public CoPints(long x,long y,long z,int index){
        this.x=x;
        this.y=y;
        this.z=z;
        this.index=index;
    }
    @Override
    public String toString() {
        return this.index+"";
    }
}


// package Quarantine;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class BalancedRemovals {
    public static void main(String[] args)throws IOException {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        int n=Integer.parseInt(br.readLine());
        TreeSet<CoPints> points=new TreeSet<>();
        StringTokenizer st;
        for(int i=1;i<=n;i++){
            st=new StringTokenizer(br.readLine());
            long x=Long.parseLong(st.nextToken());
            long y=Long.parseLong(st.nextToken());
            long z=Long.parseLong(st.nextToken());
            points.add(new CoPints(x,y,z,i));
        }
        StringBuilder print=new StringBuilder();
        for(int i=1;i<=n/2;i++){
//            System.out.println(points.toString());
            CoPints first=points.pollFirst();
            CoPints ahead=points.pollFirst();
            print.append(first.index+" "+ahead.index+"\n");
        }
        System.out.print(print.toString());
    }
}

class CoPints implements Comparable<CoPints>{
    long x,y,z;
    int index;
    public CoPints(long x,long y,long z,int index){
        this.x=x;
        this.y=y;
        this.z=z;
        this.index=index;
    }

    @Override
    public int compareTo(CoPints o) {
        if(this.index==o.index){
            return 0;
        }
        if(this.x<o.x){
            return -1;
        }
        else{
            return 1;
        }
    }

    @Override
    public String toString() {
        return this.index+"";
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

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

    static class Task {
    	public double getDis(Node a,Node b) {
    		double x=a.x-b.x;
    		double y=a.y-b.y;
    		double z=a.z-b.z;
    		return Math.sqrt(x*x+y*y+z*z);
    	}

        public void solve(int testNumber, InputReader sc, PrintWriter out) {
        	int n=sc.nextInt();
        	Node[] buf=new Node[n+1];
        	boolean[] vis=new boolean[n+1];

        	for(int i=1;i<=n;i++) {
        		double x=sc.nextInt();
        		double y=sc.nextInt();
        		double z=sc.nextInt();
        		buf[i]=new Node(x,y,z,i);
        	}
        	Arrays.sort(buf,1,n+1);
        	boolean[] ok=new boolean[n+1];
        	for(int i=1;i<=n;i+=2) {
        		if(buf[i].x==buf[i+1].x&&buf[i].y==buf[i+1].y) {
        			ok[buf[i].index]=ok[buf[i+1].index]=true;
        			out.println(buf[i].index+" "+buf[i+1].index);
        		}
        	}
        	ArrayList<Node> buf1=new ArrayList<Node>();
        	for(int i=1;i<=n;i++) {
        		if(!ok[buf[i].index])
        			buf1.add(buf[i]);
        	}
        	Collections.sort(buf1);
        	for(int i=0;i<buf1.size();i+=2) {
        		if(buf1.get(i).x==buf1.get(i+1).x) {
        			ok[buf1.get(i).index]=ok[buf1.get(i+1).index]=true;
        			out.println(buf1.get(i).index+" "+buf1.get(i+1).index);
        		}
        	}
        	ArrayList<Node> buf2=new ArrayList<Node>();
        	for(Node temp:buf1) {
        		if(!ok[temp.index])
        			buf2.add(temp);
        	}
        	Collections.sort(buf2);
        	for(int i=0;i<buf2.size();i+=2) {
        		out.println(buf2.get(i).index+" "+buf2.get(i+1).index);
        	}
        }

    }

    static class Node implements Comparable<Node>{
    	public double x;
    	public double y;
    	public double z;
    	public int index;

    	public Node(double x,double y,double z,int index) {
    		this.x=x;
    		this.y=y;
    		this.z=z;
    		this.index=index;
    	}

		@Override
		public int compareTo(Node o) {
			if(this.x==o.x) {
				if(this.y==o.y) {
					if(this.z==o.z)
						return 0;
					return this.z>o.z?1:-1;
				}
				return this.y>o.y?1:-1;
			}
			return this.x>o.x?1:-1;
		}
    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

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

    static class Task {

        public void solve(int testNumber, InputReader sc, PrintWriter out) {
        	int n=sc.nextInt();
        	Node[] buf=new Node[n+1];
        	boolean[] vis=new boolean[n+1];

        	for(int i=1;i<=n;i++) {
        		int x=sc.nextInt();
        		int y=sc.nextInt();
        		int z=sc.nextInt();
        		buf[i]=new Node(x,y,z,i);
        	}
        	Arrays.sort(buf,1,n+1);
        	boolean[] ok=new boolean[n+1];
        	for(int i=1;i+1<=n;i++) {
        		if(ok[buf[i].index])
        			continue;
        		if(buf[i].x==buf[i+1].x&&buf[i].y==buf[i+1].y) {
        			ok[buf[i].index]=ok[buf[i+1].index]=true;
        			out.println(buf[i].index+" "+buf[i+1].index);
        		}
        	}
        	ArrayList<Node> buf1=new ArrayList<Node>();
        	for(int i=1;i<=n;i++) {
        		if(!ok[buf[i].index])
        			buf1.add(buf[i]);
        	}
        	Collections.sort(buf1);
        	for(int i=0;i+1<buf1.size();i++) {
        		if(ok[buf1.get(i).index])
        			continue;
        		if(buf1.get(i).x==buf1.get(i+1).x) {
        			ok[buf1.get(i).index]=ok[buf1.get(i+1).index]=true;
        			out.println(buf1.get(i).index+" "+buf1.get(i+1).index);
        		}
        	}
        	ArrayList<Node> buf2=new ArrayList<Node>();
        	for(Node temp:buf1) {
        		if(!ok[temp.index])
        			buf2.add(temp);
        	}
        	Collections.sort(buf2);
        	for(int i=0;i<buf2.size();i+=2) {
        		out.println(buf2.get(i).index+" "+buf2.get(i+1).index);
        	}
        }

    }

    static class Node implements Comparable<Node>{
    	public int x;
    	public int y;
    	public int z;
    	public int index;

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

		@Override
		public int compareTo(Node o) {
			if(this.x!=o.x)
				return this.x-o.x;
			if(this.y!=o.y)
				return this.y-o.y;
			return this.z-o.z;
		}
    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

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

    static class Task {
    	public double getDis(Node a,Node b) {
    		double x=a.x-b.x;
    		double y=a.y-b.y;
    		double z=a.z-b.z;
    		return Math.sqrt(x*x+y*y+z*z);
    	}

        public void solve(int testNumber, InputReader sc, PrintWriter out) {
        	int n=sc.nextInt();
        	Node[] buf=new Node[n+1];
        	boolean[] vis=new boolean[n+1];

        	for(int i=1;i<=n;i++) {
        		double x=sc.nextInt();
        		double y=sc.nextInt();
        		double z=sc.nextInt();
        		buf[i]=new Node(x,y,z,i);
        	}
        	Arrays.sort(buf,1,n+1);
        	boolean[] ok=new boolean[n+1];
        	for(int i=1;i<=n;i+=2) {
        		if(buf[i].x==buf[i+1].x&&buf[i].y==buf[i+1].y) {
        			ok[buf[i].index]=ok[buf[i+1].index]=true;
        			out.println(buf[i].index+" "+buf[i+1].index);
        		}
        	}
        	ArrayList<Node> buf1=new ArrayList<Node>();
        	for(int i=1;i<=n;i++) {
        		if(!ok[buf[i].index])
        			buf1.add(buf[i]);
        	}
        	//Collections.sort(buf1);
        	for(int i=0;i<buf1.size();i+=2) {
        		if(buf1.get(i).x==buf1.get(i+1).x) {
        			ok[buf1.get(i).index]=ok[buf1.get(i+1).index]=true;
        			out.println(buf1.get(i).index+" "+buf1.get(i+1).index);
        		}
        	}
        	ArrayList<Node> buf2=new ArrayList<Node>();
        	for(Node temp:buf1) {
        		if(!ok[temp.index])
        			buf2.add(temp);
        	}
        	//Collections.sort(buf2);
        	for(int i=0;i<buf2.size();i+=2) {
        		out.println(buf2.get(i).index+" "+buf2.get(i+1).index);
        	}
        }

    }

    static class Node implements Comparable<Node>{
    	public double x;
    	public double y;
    	public double z;
    	public int index;

    	public Node(double x,double y,double z,int index) {
    		this.x=x;
    		this.y=y;
    		this.z=z;
    		this.index=index;
    	}

		@Override
		public int compareTo(Node o) {
			if(this.x==o.x) {
				if(this.y==o.y) {
					if(this.z==o.z)
						return 0;
					return this.z>o.z?1:-1;
				}
				return this.y>o.y?1:-1;
			}
			return this.x>o.x?1:-1;
		}
    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

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

    static class Task {
    	public static final int D=3;
    	public int[][] p;

    	public int dfs(ArrayList<Integer> ids,int k,PrintWriter out) {
    		if(k==D)
    			return ids.get(0);
    		HashMap<Integer,ArrayList<Integer>> map=new HashMap<Integer,ArrayList<Integer>>();
    		for(int i:ids) {
    			ArrayList<Integer> buf=map.getOrDefault(p[i][k], new ArrayList<Integer>());
    			buf.add(i);
    			map.put(p[i][k], buf);
    		}
    		ArrayList<Integer> buf=new ArrayList<Integer>();
    		for(ArrayList<Integer> temp:map.values()) {
    			int cur=dfs(temp,k+1,out);
    			if(cur!=-1)
    				buf.add(cur);
    		}
    		for(int i=0;i+1<buf.size();i+=2) {
    			out.println((buf.get(i)+1)+" "+(buf.get(i+1)+1));
    		}
    		return buf.size()%2==0?-1:buf.get(buf.size()-1);
    	}

        public void solve(int testNumber, InputReader sc, PrintWriter out) {
        	int n=sc.nextInt();
        	p=new int[n+1][D];
        	ArrayList<Integer> t=new ArrayList<Integer>(n);
        	for(int i=0;i<n;i++)
        		t.add(i);
        	for(int i=0;i<n;i++) {
        		for(int k=0;k<3;k++)
        			p[i][k]=sc.nextInt();
        	}
        	dfs(t,0,out);
        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

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

    static class Task {

        public void solve(int testNumber, InputReader sc, PrintWriter out) {
        	int n=sc.nextInt();
        	Node[] buf=new Node[n+1];
        	boolean[] vis=new boolean[n+1];

        	for(int i=1;i<=n;i++) {
        		int x=sc.nextInt();
        		int y=sc.nextInt();
        		int z=sc.nextInt();
        		buf[i]=new Node(x,y,z,i);
        	}
        	Arrays.sort(buf,1,n+1);
        	boolean[] ok=new boolean[n+1];
        	for(int i=1;i+1<=n;i++) {
        		if(ok[buf[i].index])
        			continue;
        		if(buf[i].x==buf[i+1].x&&buf[i].y==buf[i+1].y) {
        			ok[buf[i].index]=ok[buf[i+1].index]=true;
        			out.println(buf[i].index+" "+buf[i+1].index);
        		}
        	}
        	ArrayList<Node> buf1=new ArrayList<Node>();
        	for(int i=1;i<=n;i++) {
        		if(!ok[buf[i].index])
        			buf1.add(buf[i]);
        	}
        	Collections.sort(buf1);
        	for(int i=0;i<buf1.size();i+=2) {
        		if(buf1.get(i).x==buf1.get(i+1).x) {
        			ok[buf1.get(i).index]=ok[buf1.get(i+1).index]=true;
        			out.println(buf1.get(i).index+" "+buf1.get(i+1).index);
        		}
        	}
        	ArrayList<Node> buf2=new ArrayList<Node>();
        	for(Node temp:buf1) {
        		if(!ok[temp.index])
        			buf2.add(temp);
        	}
        	Collections.sort(buf2);
        	for(int i=0;i<buf2.size();i+=2) {
        		out.println(buf2.get(i).index+" "+buf2.get(i+1).index);
        	}
        }

    }

    static class Node implements Comparable<Node>{
    	public int x;
    	public int y;
    	public int z;
    	public int index;

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

		@Override
		public int compareTo(Node o) {
			if(this.x!=o.x)
				return this.x-o.x;
			if(this.y!=o.y)
				return this.y-o.y;
			return this.z-o.z;
		}
    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

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

    static class Task {

        public void solve(int testNumber, InputReader sc, PrintWriter out) {
        	int n=sc.nextInt();
        	Node[] buf=new Node[n+1];
        	boolean[] vis=new boolean[n+1];

        	for(int i=1;i<=n;i++) {
        		int x=sc.nextInt();
        		int y=sc.nextInt();
        		int z=sc.nextInt();
        		buf[i]=new Node(x,y,z,i);
        	}
        	Arrays.sort(buf,1,n+1);
        	boolean[] ok=new boolean[n+1];
        	for(int i=1;i<=n;i+=2) {
        		if(buf[i].x==buf[i+1].x&&buf[i].y==buf[i+1].y) {
        			ok[buf[i].index]=ok[buf[i+1].index]=true;
        			out.println(buf[i].index+" "+buf[i+1].index);
        		}
        	}
        	ArrayList<Node> buf1=new ArrayList<Node>();
        	for(int i=1;i<=n;i++) {
        		if(!ok[buf[i].index])
        			buf1.add(buf[i]);
        	}
        	Collections.sort(buf1);
        	for(int i=0;i<buf1.size();i+=2) {
        		if(buf1.get(i).x==buf1.get(i+1).x) {
        			ok[buf1.get(i).index]=ok[buf1.get(i+1).index]=true;
        			out.println(buf1.get(i).index+" "+buf1.get(i+1).index);
        		}
        	}
        	ArrayList<Node> buf2=new ArrayList<Node>();
        	for(Node temp:buf1) {
        		if(!ok[temp.index])
        			buf2.add(temp);
        	}
        	Collections.sort(buf2);
        	for(int i=0;i<buf2.size();i+=2) {
        		out.println(buf2.get(i).index+" "+buf2.get(i+1).index);
        	}
        }

    }

    static class Node implements Comparable<Node>{
    	public int x;
    	public int y;
    	public int z;
    	public int index;

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

		@Override
		public int compareTo(Node o) {
			if(this.x!=o.x)
				return this.x-o.x;
			if(this.y!=o.y)
				return this.y-o.y;
			return this.z-o.z;
		}
    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

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

    static class Task {
    	public static final int D=3;
    	public int[][] p;
    	public static final int INF=(int) 1e8;

    	public int dfs(ArrayList<Integer> ids,int k,PrintWriter out) {
    		if(k==D)
    			return ids.get(0);
    		HashMap<Integer,ArrayList<Integer>> map=new HashMap<Integer,ArrayList<Integer>>();
    		for(int i:ids) {
    			ArrayList<Integer> buf=map.getOrDefault(p[i][k], new ArrayList<Integer>());
    			buf.add(i);
    			map.put(p[i][k], buf);
    		}
    		ArrayList<Integer> buf=new ArrayList<Integer>();
    		for(ArrayList<Integer> temp:map.values()) {
    			int cur=dfs(temp,k+1,out);
    			if(cur!=-1)
    				buf.add(cur);
    		}
    		for(int i=0;i+1<buf.size();i+=2) {
    			out.println((buf.get(i)+1)+" "+(buf.get(i+1)+1));
    		}
    		return buf.size()%2==0?-1:buf.get(buf.size()-1);
    	}

        public void solve(int testNumber, InputReader sc, PrintWriter out) {
        	int n=sc.nextInt();
        	p=new int[n+1][D];
        	ArrayList<Integer> t=new ArrayList<Integer>(n);
        	for(int i=0;i<n;i++)
        		t.add(i);
        	for(int i=0;i<n;i++) {
        		for(int k=0;k<3;k++)
        			p[i][k]=sc.nextInt()+INF;
        	}
        	dfs(t,0,out);
        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

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

    static class Task {

        public void solve(int testNumber, InputReader sc, PrintWriter out) {
        	int n=sc.nextInt();
        	Node[] buf=new Node[n+1];
        	boolean[] vis=new boolean[n+1];

        	for(int i=1;i<=n;i++) {
        		int x=sc.nextInt();
        		int y=sc.nextInt();
        		int z=sc.nextInt();
        		buf[i]=new Node(x,y,z,i);
        	}
        	Arrays.sort(buf,1,n+1);
        	boolean[] ok=new boolean[n+1];
        	for(int i=1;i+1<=n;i++) {
        		if(ok[buf[i].index])
        			continue;
        		if(buf[i].x==buf[i+1].x&&buf[i].y==buf[i+1].y) {
        			ok[buf[i].index]=ok[buf[i+1].index]=true;
        			out.println(buf[i].index+" "+buf[i+1].index);
        		}
        	}
        	ArrayList<Node> buf1=new ArrayList<Node>();
        	for(int i=1;i<=n;i++) {
        		if(!ok[buf[i].index])
        			buf1.add(buf[i]);
        	}
        	//Collections.sort(buf1);
        	for(int i=0;i+1<buf1.size();i++) {
        		if(ok[buf1.get(i).index])
        			continue;
        		if(buf1.get(i).x==buf1.get(i+1).x) {
        			ok[buf1.get(i).index]=ok[buf1.get(i+1).index]=true;
        			out.println(buf1.get(i).index+" "+buf1.get(i+1).index);
        		}
        	}
        	ArrayList<Node> buf2=new ArrayList<Node>();
        	for(Node temp:buf1) {
        		if(!ok[temp.index])
        			buf2.add(temp);
        	}
        //	Collections.sort(buf2);
        	for(int i=0;i<buf2.size();i+=2) {
        		out.println(buf2.get(i).index+" "+buf2.get(i+1).index);
        	}
        }

    }

    static class Node implements Comparable<Node>{
    	public int x;
    	public int y;
    	public int z;
    	public int index;

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

		@Override
		public int compareTo(Node o) {
			if(this.x!=o.x)
				return this.x-o.x;
			if(this.y!=o.y)
				return this.y-o.y;
			return this.z-o.z;
		}
    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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

    }
}


//package cfglobal5;
import java.io.*;
import java.util.*;

public class C{
	// ------------------------

	public static void main(String[] args) {
		MyScanner sc = new MyScanner();
		out = new PrintWriter(new BufferedOutputStream(System.out));
		// ------------------------
		int n = sc.nextInt();
		TreeMap<Integer, TreeMap<Integer, TreeMap<Integer, Integer>>> map = new TreeMap<Integer, TreeMap<Integer, TreeMap<Integer, Integer>>>();
		for(int i = 0; i < n; i++) {
			int x = sc.nextInt(), y = sc.nextInt(), z = sc.nextInt();
			if(!map.containsKey(x))
				map.put(x, new TreeMap<Integer, TreeMap<Integer, Integer>>());
			if(!map.get(x).containsKey(y))
				map.get(x).put(y, new TreeMap<Integer, Integer>());
			map.get(x).get(y).put(z, i + 1);
		}
		while(!map.isEmpty()) {
			P p = pollFirst(map);
			int x = bestX(p.x, map), y = bestY(p.y, x, map), z = bestZ(p.z, x, y, map), i = map.get(x).get(y).get(z);
			clear(map, x, y, z);
			out.println(p + " " + i);
		}
		// ------------------------
		out.close();
	}
	static int bestX(int x, TreeMap<Integer, TreeMap<Integer, TreeMap<Integer, Integer>>> map) {
		return map.ceilingKey(x) == null ? map.floorKey(x) : map.ceilingKey(x);
	}
	static int bestY(int y, int x, TreeMap<Integer, TreeMap<Integer, TreeMap<Integer, Integer>>> map) {
		return map.get(x).ceilingKey(y) == null ? map.get(x).floorKey(y) : map.get(x).ceilingKey(y);
	}
	static int bestZ(int z, int x, int y, TreeMap<Integer, TreeMap<Integer, TreeMap<Integer, Integer>>> map) {
		return map.get(x).get(y).ceilingKey(z) == null ? map.get(x).get(y).floorKey(z) : map.get(x).get(y).ceilingKey(z);
	}
	static void clear(TreeMap<Integer, TreeMap<Integer, TreeMap<Integer, Integer>>> map, int x, int y, int z) {
		map.get(x).get(y).remove(z);
		if(map.get(x).get(y).isEmpty())
			map.get(x).remove(y);
		if(map.get(x).isEmpty())
			map.remove(x);
	}
	static P pollFirst(TreeMap<Integer, TreeMap<Integer, TreeMap<Integer, Integer>>> map) {
		int x = map.firstKey(), y = map.get(x).firstKey(), z = map.get(x).get(y).firstKey();
		P p = new P(x, y, z, map.get(x).get(y).get(z));
		clear(map, x, y, z);
		return p;
	}
	//------------------------
	static class P implements Comparable<P>{
		int x, y, z, ind;
		public P(int X, int Y, int Z, int I) {
			x = X;
			y = Y;
			z = Z;
			ind = I;
		}
		public int compareTo(P p) {
			if(x == p.x && y == p.y)
				return z - p.z;
			if(x == p.x)
				return y - p.y;
			return x - p.x;
		}
		public String toString() {
			return ind + "";
		}
	}
	public static PrintWriter out;
	public static class MyScanner {
		BufferedReader br;
		StringTokenizer st;
		public MyScanner() {
			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;
		}
	}
}


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

public class Main{
	public static class FastReader {
		BufferedReader br;
		StringTokenizer root;

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

		String next() {
			while (root == null || !root.hasMoreTokens()) {
				try {
					root = new StringTokenizer(br.readLine());
				} catch (Exception r) {
					r.printStackTrace();
				}
			}
			return root.nextToken();
		}

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

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

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

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

	public static PrintWriter out = new PrintWriter (new BufferedOutputStream(System.out));
	static long mod = (long) (1e9+7);
	static long cf = 998244353;
    static final int MAX = 100;
   // public static List<Integer>[] edges;
	public static void main(String[] args) {
		FastReader sc = new FastReader();
	    int n = sc.nextInt();
	    Pair[] p = new Pair[n];
	    for(int i=1;i<=n;++i) {
	    	int x = sc.nextInt();
	    	int y = sc.nextInt();
	    	int z = sc.nextInt();
	    	p[i-1] = new Pair(x,y,z,i);
	    }

	    Arrays.sort(p,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;
			}

	    });

	    List<Pair> xrem = new ArrayList<>();
	    for(int i=0;i<n;++i) {
	    	int j = i;
	    	while(j+1<n && p[j].x == p[j+1].x) ++j;
	    //	out.println("x "+i+" "+j);
	    	List<Pair> yrem = new ArrayList<>();
	    	for(int k=i;k<=j;++k) {
	    		int jj = k;
	    		while(jj+1<=j && p[jj].y == p[jj+1].y) ++jj;
	    		Pair[] z = Arrays.copyOfRange(p,k,jj+1);
	    		//for(int temp = k;temp<=jj;++temp) z[temp-k] = p[temp];

	    	//	out.println(jj+" "+k+" ");
	    		//for(int iii=0;iii<z.length;++iii) out.println(z[iii].id);
	    		Arrays.sort(z,new Comparator<Pair>() {
					@Override
					public int compare(Pair o1, Pair o2) {
						return o1.z-o2.z;
					}

	    		});
	    		for(int kk = 0;kk+1<z.length;kk+=2) {
	    			out.println(z[kk].id+" "+z[kk+1].id);
	    		}
	    		if(z.length%2 != 0) yrem.add(z[z.length-1]);
	    		k = jj;
	    	}
	    	for(int yy = 0;yy+1<yrem.size();yy+=2) {
	    		out.println(yrem.get(yy).id+" "+yrem.get(yy+1).id);
	    	}
	    	if(yrem.size()%2 != 0) xrem.add(yrem.get(yrem.size()-1));
	    	i = j;
	    }

	    for(int i=0;i+1<xrem.size();i+=2) {
	    	out.println(xrem.get(i).id+" "+xrem.get(i+1).id);
	    }
        out.close();
	}

	static class Pair{
		int x,y,z,id;
		Pair(int x,int y,int z,int id){
			this.x = x;
			this.y = y;
			this.z = z;
			this.id = id;
		}
	}

}


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.InputMismatchException;
import java.io.IOException;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.Map;
import java.util.Map.Entry;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Egor Kulikov (egor@egork.net)
 */
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);
        TaskC1 solver = new TaskC1();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskC1 {
        NavigableMap<Integer, TaskC1.X> map = new TreeMap<>();

        void add(int x, int y, int z, int id) {
            if (!map.containsKey(x)) {
                map.put(x, new TaskC1.X());
            }
            map.get(x).add(y, z, id);
        }

        void remove(int x, int y, int z) {
            TaskC1.X val = map.get(x);
            val.remove(y, z);
            if (val.redundant()) {
                map.remove(x);
            }
        }

        int closest(int x, int y, int z) {
            Map.Entry<Integer, TaskC1.X> entry = map.floorEntry(x);
            if (entry == null) {
                entry = map.firstEntry();
            }
            TaskC1.X val = entry.getValue();
            int result = val.closest(y, z);
            if (val.redundant()) {
                map.remove(entry.getKey());
            }
            return result;
        }

        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            int[] x = new int[n];
            int[] y = new int[n];
            int[] z = new int[n];
            in.readIntArrays(x, y, z);
            for (int i = 0; i < n; i++) {
                add(x[i], y[i], z[i], i);
            }
            boolean[] done = new boolean[n];
            int[][] answer = new int[n / 2][2];
            int at = 0;
            for (int i = 0; i < n; i++) {
                if (done[i]) {
                    continue;
                }
                answer[at][0] = i + 1;
                remove(x[i], y[i], z[i]);
                int closest = closest(x[i], y[i], z[i]);
                answer[at++][1] = closest + 1;
                done[closest] = true;
            }
            for (int[] pair : answer) {
                out.printLine(pair);
            }
        }

        static class Y {
            NavigableMap<Integer, Integer> map = new TreeMap<>();

            void add(int z, int id) {
                map.put(z, id);
            }

            boolean redundant() {
                return map.isEmpty();
            }

            public void remove(int z) {
                map.remove(z);
            }

            public int closest(int z) {
                Map.Entry<Integer, Integer> entry = map.floorEntry(z);
                if (entry == null) {
                    entry = map.firstEntry();
                }
                int result = entry.getValue();
                map.remove(entry.getKey());
                return result;
            }

        }

        static class X {
            NavigableMap<Integer, TaskC1.Y> map = new TreeMap<>();

            void add(int y, int z, int id) {
                if (!map.containsKey(y)) {
                    map.put(y, new TaskC1.Y());
                }
                map.get(y).add(z, id);
            }

            boolean redundant() {
                return map.isEmpty();
            }

            public void remove(int y, int z) {
                TaskC1.Y val = map.get(y);
                val.remove(z);
                if (val.redundant()) {
                    map.remove(y);
                }
            }

            public int closest(int y, int z) {
                Map.Entry<Integer, TaskC1.Y> entry = map.floorEntry(y);
                if (entry == null) {
                    entry = map.firstEntry();
                }
                TaskC1.Y val = entry.getValue();
                int result = val.closest(z);
                if (val.redundant()) {
                    map.remove(entry.getKey());
                }
                return result;
            }

        }

    }

    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(int[] array) {
            for (int i = 0; i < array.length; i++) {
                if (i != 0) {
                    writer.print(' ');
                }
                writer.print(array[i]);
            }
        }

        public void printLine(int[] array) {
            print(array);
            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 void readIntArrays(int[]... arrays) {
            for (int i = 0; i < arrays[0].length; i++) {
                for (int j = 0; j < arrays.length; j++) {
                    arrays[j][i] = readInt();
                }
            }
        }

        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.util.*;
import java.io.*;

public class C2{
   public static void main(String[] args) throws IOException{
      BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
      int n = Integer.parseInt(f.readLine());
      Point[] points = new Point[n];
      HashSet<Integer> deleted = new HashSet<Integer>();
      for(int i = 0; i < n; i++){
         StringTokenizer st = new StringTokenizer(f.readLine());
         points[i] = new Point(Long.parseLong(st.nextToken()), Long.parseLong(st.nextToken()), Long.parseLong(st.nextToken()), i+1);
      }
      Arrays.sort(points);
      int i = 0;
      while(i < n-1){
         Point p1 = points[i];
         Point p2 = points[i+1];
         if(p1.x == p2.x && p1.y == p2.y){
            deleted.add(p1.id);
            deleted.add(p2.id);
            System.out.println(p1.id + " " + p2.id);
            i+=2;
         }else{
            i+=1;
         }
      }

      ArrayList<Point> points2 = new ArrayList<Point>();
      for(int j = 0; j < n; j++){
         if(!deleted.contains(points[j].id)) points2.add(points[j]);
      }

      i = 0;
      while(i < points2.size()-1){
         Point p1 = points2.get(i);
         Point p2 = points2.get(i+1);
         if(p1.x == p2.x){
            deleted.add(p1.id);
            deleted.add(p2.id);
            System.out.println(p1.id + " " + p2.id);
            i+=2;
         }else{
            i+=1;
         }
      }

      ArrayList<Point> points3 = new ArrayList<Point>();
      for(int j = 0; j < points2.size(); j++){
         if(!deleted.contains(points2.get(j).id)) points3.add(points2.get(j));
      }

      i = 0;
      while(i < points3.size()-1){
         Point p1 = points3.get(i);
         Point p2 = points3.get(i+1);
         deleted.add(p1.id);
         deleted.add(p2.id);
         System.out.println(p1.id + " " + p2.id);
         i+=2;
      }

   }
}
class Point implements Comparable<Point>{
   public long x;
   public long y;
   public long z;
   public int id;

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

   public double getDist(Point p){
      return Math.sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y) + (z-p.z)*(z-p.z));
   }

   public int compareTo(Point p){
      if(x != p.x) return x > p.x ? 1 : -1;
      if(y != p.y) return y > p.y ? 1 : -1;
      return z > p.z ? 1 : -1;
   }

}