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