← Home
package main

import (
	"bytes"
	"io"
	"os"
	"sort"
)

type Rect struct {
	u, l, d, r int
}

type FastScanner struct {
	data []byte
	idx  int
	n    int
}

func NewFastScanner() *FastScanner {
	data, _ := io.ReadAll(os.Stdin)
	return &FastScanner{data: data, n: len(data)}
}

func (fs *FastScanner) NextInt() int {
	for fs.idx < fs.n {
		c := fs.data[fs.idx]
		if c >= '0' && c <= '9' || c == '-' {
			break
		}
		fs.idx++
	}
	sign := 1
	if fs.data[fs.idx] == '-' {
		sign = -1
		fs.idx++
	}
	val := 0
	for fs.idx < fs.n {
		c := fs.data[fs.idx]
		if c < '0' || c > '9' {
			break
		}
		val = val*10 + int(c-'0')
		fs.idx++
	}
	return val * sign
}

func greedy(ids []int, rects []Rect, start []int) []int {
	seq := make([]int, 0, len(ids))
	cur := 0
	for _, id := range ids {
		r := rects[id].r
		if r <= cur {
			continue
		}
		s := rects[id].l
		if cur+1 > s {
			s = cur + 1
		}
		if s <= r {
			start[id] = s
			seq = append(seq, id)
			cur = r
		}
	}
	return seq
}

func processRow(seq []int, rowStart []int, common []bool, newStart []int, rects []Rect, fs []int, fe []int) {
	block := make([]int, 0)
	prevEnd := -2
	for i, id := range seq {
		if i == 0 || rowStart[id] > prevEnd+1 {
			block = block[:0]
		}
		if common[id] {
			delta := rowStart[id] - newStart[id]
			for j := len(block) - 1; j >= 0 && delta > 0; j-- {
				rid := block[j]
				curLen := fe[rid] - fs[rid] + 1
				if curLen <= delta {
					fs[rid], fe[rid] = 0, 0
					delta -= curLen
				} else {
					fe[rid] -= delta
					delta = 0
				}
			}
			block = block[:0]
		} else {
			fs[id] = rowStart[id]
			fe[id] = rects[id].r
			block = append(block, id)
		}
		prevEnd = rects[id].r
	}
}

func writeInt(buf *bytes.Buffer, x int64) {
	if x == 0 {
		buf.WriteByte('0')
		return
	}
	if x < 0 {
		buf.WriteByte('-')
		x = -x
	}
	var s [32]byte
	n := 0
	for x > 0 {
		s[n] = byte('0' + x%10)
		n++
		x /= 10
	}
	for i := n - 1; i >= 0; i-- {
		buf.WriteByte(s[i])
	}
}

func main() {
	in := NewFastScanner()
	t := in.NextInt()
	var out bytes.Buffer

	for ; t > 0; t-- {
		n := in.NextInt()
		rects := make([]Rect, n)
		topIds := make([]int, 0, n)
		botIds := make([]int, 0, n)

		for i := 0; i < n; i++ {
			u := in.NextInt()
			l := in.NextInt()
			d := in.NextInt()
			r := in.NextInt()
			rects[i] = Rect{u, l, d, r}
			if u == 1 {
				topIds = append(topIds, i)
			}
			if d == 2 {
				botIds = append(botIds, i)
			}
		}

		cmp := func(a, b int) bool {
			if rects[a].l != rects[b].l {
				return rects[a].l < rects[b].l
			}
			if rects[a].r != rects[b].r {
				return rects[a].r > rects[b].r
			}
			return a < b
		}

		sort.Slice(topIds, func(i, j int) bool { return cmp(topIds[i], topIds[j]) })
		sort.Slice(botIds, func(i, j int) bool { return cmp(botIds[i], botIds[j]) })

		topStart := make([]int, n)
		botStart := make([]int, n)

		topSeq := greedy(topIds, rects, topStart)
		botSeq := greedy(botIds, rects, botStart)

		common := make([]bool, n)
		newStart := make([]int, n)
		for i := 0; i < n; i++ {
			if rects[i].u == 1 && rects[i].d == 2 && topStart[i] > 0 && botStart[i] > 0 {
				common[i] = true
				if topStart[i] < botStart[i] {
					newStart[i] = topStart[i]
				} else {
					newStart[i] = botStart[i]
				}
			}
		}

		topFS := make([]int, n)
		topFE := make([]int, n)
		botFS := make([]int, n)
		botFE := make([]int, n)

		processRow(topSeq, topStart, common, newStart, rects, topFS, topFE)
		processRow(botSeq, botStart, common, newStart, rects, botFS, botFE)

		outU := make([]int, n)
		outL := make([]int, n)
		outD := make([]int, n)
		outR := make([]int, n)

		var area int64
		for i := 0; i < n; i++ {
			if common[i] {
				outU[i], outL[i], outD[i], outR[i] = 1, newStart[i], 2, rects[i].r
			} else if topFS[i] > 0 {
				outU[i], outL[i], outD[i], outR[i] = 1, topFS[i], 1, topFE[i]
			} else if botFS[i] > 0 {
				outU[i], outL[i], outD[i], outR[i] = 2, botFS[i], 2, botFE[i]
			}
			if outU[i] != 0 {
				area += int64(outR[i]-outL[i]+1) * int64(outD[i]-outU[i]+1)
			}
		}

		writeInt(&out, area)
		out.WriteByte('\n')
		for i := 0; i < n; i++ {
			writeInt(&out, int64(outU[i]))
			out.WriteByte(' ')
			writeInt(&out, int64(outL[i]))
			out.WriteByte(' ')
			writeInt(&out, int64(outD[i]))
			out.WriteByte(' ')
			writeInt(&out, int64(outR[i]))
			out.WriteByte('\n')
		}
	}

	os.Stdout.Write(out.Bytes())
}