package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"time"
)
type Box struct {
items []int
pos map[int]int
}
type Move struct {
src, dst, item int
}
func main() {
reader := bufio.NewReader(os.Stdin)
getInt := func() int {
var res int
var started bool
for {
b, err := reader.ReadByte()
if err != nil {
break
}
if b >= '0' && b <= '9' {
res = res*10 + int(b-'0')
started = true
} else if started {
break
}
}
return res
}
n := getInt()
m_presents := getInt()
_ = m_presents
if n == 0 {
return
}
boxes := make([]Box, n+1)
s := make([]int, n+1)
S := 0
for i := 1; i <= n; i++ {
s[i] = getInt()
S += s[i]
boxes[i].items = make([]int, 0, s[i])
boxes[i].pos = make(map[int]int, s[i])
for j := 0; j < s[i]; j++ {
val := getInt()
boxes[i].items = append(boxes[i].items, val)
boxes[i].pos[val] = j
}
}
if S == 0 {
fmt.Println(0)
return
}
L := S / n
R := (S + n - 1) / n
if S%n == 0 {
R = L
}
d_prime := make([]int, n+1)
sum_prime := 0
for i := 1; i <= n; i++ {
if s[i] > R {
d_prime[i] = R
} else if s[i] < L {
d_prime[i] = L
} else {
d_prime[i] = s[i]
}
sum_prime += d_prime[i]
}
if sum_prime < S {
for i := 1; i <= n && sum_prime < S; i++ {
if d_prime[i] == L {
d_prime[i] = R
sum_prime++
}
}
} else if sum_prime > S {
for i := 1; i <= n && sum_prime > S; i++ {
if d_prime[i] == R {
d_prime[i] = L
sum_prime--
}
}
}
var sources []int
var sinks []int
for i := 1; i <= n; i++ {
diff := s[i] - d_prime[i]
for j := 0; j < diff; j++ {
sources = append(sources, i)
}
for j := 0; j < -diff; j++ {
sinks = append(sinks, i)
}
}
moves := make([]Move, 0, len(sources))
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
for k := 0; k < len(sources); k++ {
src := sources[k]
dst := sinks[k]
var item int
for {
idx := rng.Intn(len(boxes[src].items))
item = boxes[src].items[idx]
if _, has := boxes[dst].pos[item]; !has {
break
}
}
moves = append(moves, Move{src, dst, item})
idx := boxes[src].pos[item]
last := boxes[src].items[len(boxes[src].items)-1]
boxes[src].items[idx] = last
boxes[src].pos[last] = idx
boxes[src].items = boxes[src].items[:len(boxes[src].items)-1]
delete(boxes[src].pos, item)
boxes[dst].items = append(boxes[dst].items, item)
boxes[dst].pos[item] = len(boxes[dst].items) - 1
}
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
fmt.Fprintln(out, len(moves))
for _, move := range moves {
fmt.Fprintln(out, move.src, move.dst, move.item)
}
}