← Home
package main

import (
	"bufio"
	"io"
	"os"
	"sort"
	"strconv"
	"strings"
)

type FastScanner struct {
	data []byte
	pos  int
	n    int
}

func NewFastScanner() *FastScanner {
	data, _ := io.ReadAll(os.Stdin)
	return &FastScanner{data: data, n: len(data)}
}

func (fs *FastScanner) NextInt() int {
	for fs.pos < fs.n {
		c := fs.data[fs.pos]
		if c == '-' || (c >= '0' && c <= '9') {
			break
		}
		fs.pos++
	}
	sign := 1
	if fs.data[fs.pos] == '-' {
		sign = -1
		fs.pos++
	}
	val := 0
	for fs.pos < fs.n {
		c := fs.data[fs.pos]
		if c < '0' || c > '9' {
			break
		}
		val = val*10 + int(c-'0')
		fs.pos++
	}
	return sign * val
}

type Point struct {
	x, y int
	idx  int
}

func main() {
	fs := NewFastScanner()
	t := fs.NextInt()

	var sb strings.Builder

	for ; t > 0; t-- {
		n := fs.NextInt()
		pts := make([]Point, n)
		for i := 0; i < n; i++ {
			pts[i] = Point{x: fs.NextInt(), y: fs.NextInt(), idx: i + 1}
		}

		xLow := make([]bool, n+1)
		yLow := make([]bool, n+1)

		ord := make([]Point, n)
		copy(ord, pts)
		sort.Slice(ord, func(i, j int) bool {
			if ord[i].x != ord[j].x {
				return ord[i].x < ord[j].x
			}
			if ord[i].y != ord[j].y {
				return ord[i].y < ord[j].y
			}
			return ord[i].idx < ord[j].idx
		})
		for i := 0; i < n/2; i++ {
			xLow[ord[i].idx] = true
		}

		copy(ord, pts)
		sort.Slice(ord, func(i, j int) bool {
			if ord[i].y != ord[j].y {
				return ord[i].y < ord[j].y
			}
			if ord[i].x != ord[j].x {
				return ord[i].x < ord[j].x
			}
			return ord[i].idx < ord[j].idx
		})
		for i := 0; i < n/2; i++ {
			yLow[ord[i].idx] = true
		}

		a := make([]int, 0)
		b := make([]int, 0)
		c := make([]int, 0)
		d := make([]int, 0)

		for _, p := range pts {
			xl := xLow[p.idx]
			yl := yLow[p.idx]
			if xl {
				if yl {
					a = append(a, p.idx)
				} else {
					b = append(b, p.idx)
				}
			} else {
				if yl {
					c = append(c, p.idx)
				} else {
					d = append(d, p.idx)
				}
			}
		}

		for i := 0; i < len(a); i++ {
			sb.WriteString(strconv.Itoa(a[i]))
			sb.WriteByte(' ')
			sb.WriteString(strconv.Itoa(d[i]))
			sb.WriteByte('\n')
		}
		for i := 0; i < len(b); i++ {
			sb.WriteString(strconv.Itoa(b[i]))
			sb.WriteByte(' ')
			sb.WriteString(strconv.Itoa(c[i]))
			sb.WriteByte('\n')
		}
	}

	w := bufio.NewWriterSize(os.Stdout, 1<<20)
	w.WriteString(sb.String())
	w.Flush()
}