package main
import (
"bufio"
"fmt"
"os"
)
type Part []int
type Component struct {
parts []Part
id int
}
type Query struct {
u, v int
ref interface{}
}
func main() {
reader := bufio.NewReader(os.Stdin)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
var n int
if _, err := fmt.Fscanf(reader, "%d\n", &n); err != nil {
return
}
components := make([]*Component, n)
for i := 0; i < n; i++ {
components[i] = &Component{
parts: []Part{{i + 1}},
id: i,
}
}
type Partial struct {
part Part
testedWith int
}
var partials []Partial
for batch := 0; batch < 7; batch++ {
if len(components) == 1 && len(partials) == 0 {
break
}
var t3, t2, t1 []*Component
for _, c := range components {
if len(c.parts) == 3 {
t3 = append(t3, c)
} else if len(c.parts) == 2 {
t2 = append(t2, c)
} else {
t1 = append(t1, c)
}
}
var hub *Component
if len(t3) > 0 {
hub = t3[0]
for i := 1; i < len(t3); i++ {
if len(t3[i].parts[0]) > len(hub.parts[0]) {
hub = t3[i]
}
}
}
var queries []Query
used := make([]bool, n+1)
getAvail := func(part Part, count int) []int {
var res []int
for _, v := range part {
if !used[v] {
res = append(res, v)
if len(res) == count {
break
}
}
}
return res
}
markUsed := func(vs ...int) {
for _, v := range vs {
used[v] = true
}
}
type Task struct {
typ int
args []interface{}
}
var tasks []Task
var nextPartials []Partial
for _, p := range partials {
if hub != nil {
h2 := 1
if p.testedWith == 1 {
h2 = 2
}
hAvail := getAvail(hub.parts[h2], 1)
pAvail := getAvail(p.part, 1)
if len(hAvail) > 0 && len(pAvail) > 0 {
queries = append(queries, Query{hAvail[0], pAvail[0], nil})
markUsed(hAvail[0], pAvail[0])
tasks = append(tasks, Task{10, []interface{}{p, hAvail[0], pAvail[0], h2}})
continue
}
}
nextPartials = append(nextPartials, p)
}
partials = nextPartials
var unmergedT3 []*Component
for _, c := range t3 {
if c == hub {
continue
}
h1 := getAvail(hub.parts[0], 2)
h2 := getAvail(hub.parts[1], 1)
d1 := getAvail(c.parts[0], 1)
d2 := getAvail(c.parts[1], 1)
d3 := getAvail(c.parts[2], 1)
if len(h1) == 2 && len(h2) == 1 && len(d1) == 1 && len(d2) == 1 && len(d3) == 1 {
queries = append(queries, Query{h1[0], d1[0], nil}, Query{h1[1], d2[0], nil}, Query{h2[0], d3[0], nil})
markUsed(h1[0], h1[1], h2[0], d1[0], d2[0], d3[0])
tasks = append(tasks, Task{3, []interface{}{c, h1[0], d1[0], h1[1], d2[0], h2[0], d3[0]}})
} else {
unmergedT3 = append(unmergedT3, c)
}
}
var unmergedT2 []*Component
for _, c := range t2 {
merged := false
if hub != nil {
canAbsorb := true
var tQueries []Query
var tUsed []int
var tArgs []interface{}
for _, part := range c.parts {
if len(part) >= 2 {
h1 := getAvail(hub.parts[0], 1)
h2 := getAvail(hub.parts[1], 1)
p := getAvail(part, 2)
if len(h1) > 0 && len(h2) > 0 && len(p) == 2 {
tQueries = append(tQueries, Query{h1[0], p[0], nil}, Query{h2[0], p[1], nil})
tUsed = append(tUsed, h1[0], h2[0], p[0], p[1])
markUsed(h1[0], h2[0], p[0], p[1])
tArgs = append(tArgs, part, 2, h1[0], p[0], h2[0], p[1])
} else {
canAbsorb = false
break
}
} else {
h1 := getAvail(hub.parts[0], 1)
p := getAvail(part, 1)
if len(h1) > 0 && len(p) > 0 {
tQueries = append(tQueries, Query{h1[0], p[0], nil})
tUsed = append(tUsed, h1[0], p[0])
markUsed(h1[0], p[0])
tArgs = append(tArgs, part, 1, h1[0], p[0])
} else {
canAbsorb = false
break
}
}
}
if canAbsorb {
queries = append(queries, tQueries...)
tasks = append(tasks, Task{4, tArgs})
merged = true
} else {
for _, u := range tUsed {
used[u] = false
}
}
}
if !merged {
unmergedT2 = append(unmergedT2, c)
}
}
var unmergedT1 []*Component
for _, c := range t1 {
merged := false
if hub != nil {
part := c.parts[0]
if len(part) >= 2 {
h1 := getAvail(hub.parts[0], 1)
h2 := getAvail(hub.parts[1], 1)
p := getAvail(part, 2)
if len(h1) > 0 && len(h2) > 0 && len(p) == 2 {
queries = append(queries, Query{h1[0], p[0], nil}, Query{h2[0], p[1], nil})
markUsed(h1[0], h2[0], p[0], p[1])
tasks = append(tasks, Task{5, []interface{}{part, h1[0], p[0], h2[0], p[1]}})
merged = true
}
} else {
h1 := getAvail(hub.parts[0], 1)
p := getAvail(part, 1)
if len(h1) > 0 && len(p) > 0 {
queries = append(queries, Query{h1[0], p[0], nil})
markUsed(h1[0], p[0])
tasks = append(tasks, Task{6, []interface{}{part, h1[0], p[0]}})
merged = true
}
}
}
if !merged {
unmergedT1 = append(unmergedT1, c)
}
}
for i := 0; i+1 < len(unmergedT2); i += 2 {
c, d := unmergedT2[i], unmergedT2[i+1]
c1 := getAvail(c.parts[0], 1)
c2 := getAvail(c.parts[1], 1)
d1 := getAvail(d.parts[0], 1)
d2 := getAvail(d.parts[1], 1)
if len(c1) > 0 && len(c2) > 0 && len(d1) > 0 && len(d2) > 0 {
queries = append(queries, Query{c1[0], d1[0], nil}, Query{c2[0], d2[0], nil})
markUsed(c1[0], c2[0], d1[0], d2[0])
tasks = append(tasks, Task{2, []interface{}{c, d, c1[0], d1[0], c2[0], d2[0]}})
}
}
for i := 0; i+1 < len(unmergedT1); i += 2 {
c, d := unmergedT1[i], unmergedT1[i+1]
c1 := getAvail(c.parts[0], 1)
d1 := getAvail(d.parts[0], 1)
if len(c1) > 0 && len(d1) > 0 {
queries = append(queries, Query{c1[0], d1[0], nil})
markUsed(c1[0], d1[0])
tasks = append(tasks, Task{1, []interface{}{c, d, c1[0], d1[0]}})
}
}
if len(queries) == 0 {
break
}
fmt.Fprintf(writer, "%d\n", len(queries))
for _, q := range queries {
fmt.Fprintf(writer, "%d %d\n", q.u, q.v)
}
writer.Flush()
results := make([]int, len(queries))
for i := 0; i < len(queries); i++ {
fmt.Fscanf(reader, "%d", &results[i])
}
resMap := make(map[string]int)
for i, q := range queries {
resMap[fmt.Sprintf("%d_%d", q.u, q.v)] = results[i]
}
checkRes := func(u, v int) int {
if val, ok := resMap[fmt.Sprintf("%d_%d", u, v)]; ok {
return val
}
return resMap[fmt.Sprintf("%d_%d", v, u)]
}
var nextComponents []*Component
if hub != nil {
nextComponents = append(nextComponents, hub)
}
mergedComps := make(map[int]bool)
for _, t := range tasks {
if t.typ == 1 {
c := t.args[0].(*Component)
d := t.args[1].(*Component)
mergedComps[c.id] = true
mergedComps[d.id] = true
res := checkRes(t.args[2].(int), t.args[3].(int))
if res == 1 {
c.parts[0] = append(c.parts[0], d.parts[0]...)
nextComponents = append(nextComponents, c)
} else {
c.parts = append(c.parts, d.parts[0])
nextComponents = append(nextComponents, c)
}
} else if t.typ == 2 {
c := t.args[0].(*Component)
d := t.args[1].(*Component)
mergedComps[c.id] = true
mergedComps[d.id] = true
r1 := checkRes(t.args[2].(int), t.args[3].(int))
r2 := checkRes(t.args[4].(int), t.args[5].(int))
if r1 == 1 && r2 == 1 {
c.parts[0] = append(c.parts[0], d.parts[0]...)
c.parts[1] = append(c.parts[1], d.parts[1]...)
} else if r1 == 1 && r2 == 0 {
c.parts[0] = append(c.parts[0], d.parts[0]...)
c.parts = append(c.parts, d.parts[1])
} else if r1 == 0 && r2 == 1 {
c.parts[0] = append(c.parts[0], d.parts[1]...)
c.parts = append(c.parts, d.parts[0])
} else {
c.parts[0] = append(c.parts[0], d.parts[1]...)
c.parts[1] = append(c.parts[1], d.parts[0]...)
}
nextComponents = append(nextComponents, c)
} else if t.typ == 3 {
c := t.args[0].(*Component)
mergedComps[c.id] = true
r1 := checkRes(t.args[1].(int), t.args[2].(int))
r2 := checkRes(t.args[3].(int), t.args[4].(int))
r3 := checkRes(t.args[5].(int), t.args[6].(int))
var m1, m2, m3 int
if r1 == 1 {
m1 = 0
} else if r2 == 1 {
m1 = 1
} else {
m1 = 2
}
if r3 == 1 {
m3 = 2
} else {
if m1 == 2 {
m3 = 1
} else {
m3 = 2
}
}
m2 = 3 - m1 - m3
hub.parts[m1] = append(hub.parts[m1], c.parts[0]...)
hub.parts[m2] = append(hub.parts[m2], c.parts[1]...)
hub.parts[m3] = append(hub.parts[m3], c.parts[2]...)
} else if t.typ == 4 {
args := t.args
idx := 0
for idx < len(args) {
part := args[idx].(Part)
cnt := args[idx+1].(int)
if cnt == 2 {
r1 := checkRes(args[idx+2].(int), args[idx+3].(int))
r2 := checkRes(args[idx+4].(int), args[idx+5].(int))
if r1 == 1 {
hub.parts[0] = append(hub.parts[0], part...)
} else if r2 == 1 {
hub.parts[1] = append(hub.parts[1], part...)
} else {
hub.parts[2] = append(hub.parts[2], part...)
}
idx += 6
} else {
r1 := checkRes(args[idx+2].(int), args[idx+3].(int))
if r1 == 1 {
hub.parts[0] = append(hub.parts[0], part...)
} else {
partials = append(partials, Partial{part, 0})
}
idx += 4
}
}
} else if t.typ == 5 {
part := t.args[0].(Part)
r1 := checkRes(t.args[1].(int), t.args[2].(int))
r2 := checkRes(t.args[3].(int), t.args[4].(int))
if r1 == 1 {
hub.parts[0] = append(hub.parts[0], part...)
} else if r2 == 1 {
hub.parts[1] = append(hub.parts[1], part...)
} else {
hub.parts[2] = append(hub.parts[2], part...)
}
} else if t.typ == 6 {
part := t.args[0].(Part)
r1 := checkRes(t.args[1].(int), t.args[2].(int))
if r1 == 1 {
hub.parts[0] = append(hub.parts[0], part...)
} else {
partials = append(partials, Partial{part, 0})
}
} else if t.typ == 10 {
p := t.args[0].(Partial)
r := checkRes(t.args[1].(int), t.args[2].(int))
h2 := t.args[3].(int)
if r == 1 {
hub.parts[h2] = append(hub.parts[h2], p.part...)
} else {
rem := 3 - 0 - h2
hub.parts[rem] = append(hub.parts[rem], p.part...)
}
}
}
for _, c := range unmergedT3 {
if !mergedComps[c.id] {
nextComponents = append(nextComponents, c)
}
}
for _, c := range unmergedT2 {
if !mergedComps[c.id] {
nextComponents = append(nextComponents, c)
}
}
for _, c := range unmergedT1 {
if !mergedComps[c.id] {
nextComponents = append(nextComponents, c)
}
}
if hub != nil {
for i := 0; i < len(hub.parts); i++ {
for j := i + 1; j < len(hub.parts); j++ {
if len(hub.parts[i]) < len(hub.parts[j]) {
hub.parts[i], hub.parts[j] = hub.parts[j], hub.parts[i]
}
}
}
}
components = nextComponents
}
ans := make([]Part, 3)
if len(components) > 0 {
for i, p := range components[0].parts {
if i < 3 {
ans[i] = p
}
}
}
for i := 0; i < 3; i++ {
for j, v := range ans[i] {
if j > 0 {
fmt.Fprintf(writer, " ")
}
fmt.Fprintf(writer, "%d", v)
}
fmt.Fprintf(writer, "\n")
}
}