← Home
```go
package main

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

var reader *bufio.Reader
var writer *bufio.Writer

func init() {
	reader = bufio.NewReader(os.Stdin)
	writer = bufio.NewWriter(os.Stdout)
}

func readInt() int {
	var x int
	var c byte
	for {
		c, _ = reader.ReadByte()
		if c >= '0' && c <= '9' {
			x = int(c - '0')
			break
		}
	}
	for {
		c, _ = reader.ReadByte()
		if c >= '0' && c <= '9' {
			x = x*10 + int(c-'0')
		} else {
			break
		}
	}
	return x
}

type Box struct {
	id   int
	size int
}

type Move struct {
	u, v, k int
}

func main() {
	defer writer.Flush()

	n := readInt()
	m := readInt()

	// presents[k] stores the list of box IDs that contain present k
	presents := make([][]int, m+1)
	boxes := make([]Box, n)
	totalPresents := 0

	for i := 0; i < n; i++ {
		s := readInt()
		boxes[i] = Box{id: i + 1, size: s}
		totalPresents += s
		for j := 0; j < s; j++ {
			p := readInt()
			presents[p] = append(presents[p], i+1)
		}
	}

	// Determine target sizes
	// Sort boxes by current size to assign targets optimally
	sortedBoxes := make([]Box, n)
	copy(sortedBoxes, boxes)
	sort.Slice(sortedBoxes, func(i, j int) bool {
		return sortedBoxes[i].size < sortedBoxes[j].size
	})

	q := totalPresents / n
	r := totalPresents % n

	targetSize := make([]int, n+1)
	for i := 0; i < n; i++ {
		// The r largest boxes get q+1, others get q
		t := q
		if i >= n-r {
			t = q + 1
		}
		targetSize[sortedBoxes[i].id] = t
	}

	// Calculate 'need' for each box
	// Positive need means it's a Donor (has too many)
	// Negative need means it's a Receiver (has too few)
	need := make([]int, n+1)
	var receivers []int
	for i := 0; i < n; i++ {
		id := boxes[i].id
		diff := boxes[i].size - targetSize[id]
		need[id] = diff
		if diff < 0 {
			receivers = append(receivers, id)
		}
	}

	// tag array helps avoid iterating receivers to check if they have a present
	tag := make([]int, n+1)
	var moves []Move

	// Process each kind of present
	for k := 1; k <= m; k++ {
		if len(receivers) == 0 {
			break
		}
		
		var currentDonors []int
		// Identify potential donors and mark receivers that already have k
		for _, boxID := range presents[k] {
			if need[boxID] > 0 {
				currentDonors = append(currentDonors, boxID)
			} else if need[boxID] < 0 {
				tag[boxID] = k
			}
		}

		if len(currentDonors) == 0 {
			continue
		}

		donorIdx := 0
		i := 0
		// Try to pair donors with valid receivers
		for i < len(receivers) && donorIdx < len(currentDonors) {
			rID := receivers[i]
			
			// If receiver already has present k, skip it for this kind
			if tag[rID] == k {
				i++
				continue
			}

			dID := currentDonors[donorIdx]
			
			// We found a valid pair: donor dID has k, receiver rID needs items and doesn't have k
			moves = append(moves, Move{dID, rID, k})
			need[dID]--
			need[rID]++ // need[rID] is negative, so increment towards 0
			
			// If receiver is satisfied, remove from list
			if need[rID] == 0 {
				// Efficient removal: swap with last and shrink slice
				last := len(receivers) - 1
				receivers[i] = receivers[last]
				receivers = receivers[:last]
				// Do not increment i, re-evaluate index i which is now the swapped element
			} else {
				i++
			}
			
			// Move to next donor since this donor has given away its copy of k
			donorIdx++
		}
	}

	fmt.Fprintln(writer, len(moves))
	for _, mv := range moves {
		fmt.Fprintln(writer, mv.u, mv.v, mv.k)
	}
}
```