← Home
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

type Point struct {
	x, y int64
	id   int
	a    int
}

func cross(a, b, c Point) int64 {
	return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x)
}

func main() {
	reader := bufio.NewReader(os.Stdin)
	var n int
	fmt.Fscan(reader, &n)

	pts := make([]Point, n)
	label := make([]int, n+1)
	for i := 0; i < n; i++ {
		var x, y int64
		var a int
		fmt.Fscan(reader, &x, &y, &a)
		pts[i] = Point{x, y, i + 1, a}
		label[i+1] = a
	}

	active := make([]Point, n)
	copy(active, pts)

	var hub Point
	found := false

	for len(active) > 0 {
		if len(active) == 1 {
			active = nil
			break
		}
		if len(active) == 2 {
			if label[active[0].id] != active[0].id {
				hub = active[0]
				found = true
			} else if label[active[1].id] != active[1].id {
				hub = active[1]
				found = true
			}
			if found {
				break
			}
			active = nil
			break
		}

		sort.Slice(active, func(i, j int) bool {
			if active[i].x != active[j].x {
				return active[i].x < active[j].x
			}
			return active[i].y < active[j].y
		})

		var lower []Point
		for _, p := range active {
			for len(lower) >= 2 && cross(lower[len(lower)-2], lower[len(lower)-1], p) <= 0 {
				lower = lower[:len(lower)-1]
			}
			lower = append(lower, p)
		}

		var upper []Point
		for i := len(active) - 1; i >= 0; i-- {
			p := active[i]
			for len(upper) >= 2 && cross(upper[len(upper)-2], upper[len(upper)-1], p) <= 0 {
				upper = upper[:len(upper)-1]
			}
			upper = append(upper, p)
		}

		hull := lower[:len(lower)-1]
		hull = append(hull, upper[:len(upper)-1]...)

		for i := 0; i < len(hull); i++ {
			if label[hull[i].id] != hull[i].id {
				hub = hull[i]
				found = true
				break
			}
		}

		if found {
			break
		}

		inHull := make(map[int]bool)
		for _, p := range hull {
			inHull[p.id] = true
		}

		var nextActive []Point
		for _, p := range active {
			if !inHull[p.id] {
				nextActive = append(nextActive, p)
			}
		}
		active = nextActive
	}

	if !found || len(active) == 0 {
		fmt.Println(0)
		return
	}

	var P []Point
	for _, p := range active {
		if p.id != hub.id {
			P = append(P, p)
		}
	}

	sort.Slice(P, func(i, j int) bool {
		vi := Point{P[i].x - hub.x, P[i].y - hub.y, 0, 0}
		vj := Point{P[j].x - hub.x, P[j].y - hub.y, 0, 0}
		return vi.x*vj.y-vi.y*vj.x > 0
	})

	parent := make(map[int]int)
	for _, p := range active {
		parent[p.id] = p.id
	}

	var find func(int) int
	find = func(i int) int {
		if parent[i] == i {
			return i
		}
		parent[i] = find(parent[i])
		return parent[i]
	}

	union := func(i, j int) {
		rootI := find(i)
		rootJ := find(j)
		if rootI != rootJ {
			parent[rootI] = rootJ
		}
	}

	for _, p := range active {
		union(p.id, label[p.id])
	}

	var ops [][2]int

	for i := 0; i < len(P)-1; i++ {
		u := P[i].id
		v := P[i+1].id
		if find(u) != find(v) {
			label[u], label[v] = label[v], label[u]
			ops = append(ops, [2]int{u, v})
			union(u, v)
		}
	}

	curr := hub.id
	for label[curr] != curr {
		target := label[curr]
		label[curr], label[target] = label[target], label[curr]
		ops = append(ops, [2]int{curr, target})
	}

	fmt.Println(len(ops))
	for _, op := range ops {
		fmt.Printf("%d %d\n", op[0], op[1])
	}
}