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])
}
}