package main
import (
"io"
"os"
"sort"
"strconv"
"strings"
)
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 && (fs.data[fs.idx] < '0' || fs.data[fs.idx] > '9') && fs.data[fs.idx] != '-' {
fs.idx++
}
sign := 1
if fs.data[fs.idx] == '-' {
sign = -1
fs.idx++
}
val := 0
for fs.idx < fs.n && fs.data[fs.idx] >= '0' && fs.data[fs.idx] <= '9' {
val = val*10 + int(fs.data[fs.idx]-'0')
fs.idx++
}
return sign * val
}
type Seg struct {
c int
l int
r int
}
func main() {
fs := NewFastScanner()
t := fs.NextInt()
var out strings.Builder
for ; t > 0; t-- {
n := fs.NextInt()
segs := make([]Seg, n)
for i := 0; i < n; i++ {
segs[i] = Seg{
c: fs.NextInt(),
l: fs.NextInt(),
r: fs.NextInt(),
}
}
byL := make([]int, n)
byR := make([]int, n)
for i := 0; i < n; i++ {
byL[i] = i
byR[i] = i
}
sort.Slice(byL, func(i, j int) bool {
a, b := byL[i], byL[j]
if segs[a].l != segs[b].l {
return segs[a].l < segs[b].l
}
return a < b
})
sort.Slice(byR, func(i, j int) bool {
a, b := byR[i], byR[j]
if segs[a].r != segs[b].r {
return segs[a].r < segs[b].r
}
return a < b
})
parent := make([]int, n)
sz := make([]int, n)
activeR := make([]int, n)
activeB := make([]int, n)
for i := 0; i < n; i++ {
parent[i] = i
sz[i] = 1
}
redSet := make(map[int]struct{})
blueSet := make(map[int]struct{})
var find func(int) int
find = func(x int) int {
if parent[x] != x {
parent[x] = find(parent[x])
}
return parent[x]
}
components := 0
unite := func(a, b int) int {
a = find(a)
b = find(b)
if a == b {
return a
}
if sz[a] < sz[b] {
a, b = b, a
}
if activeR[a] > 0 {
delete(redSet, a)
}
if activeB[a] > 0 {
delete(blueSet, a)
}
if activeR[b] > 0 {
delete(redSet, b)
}
if activeB[b] > 0 {
delete(blueSet, b)
}
parent[b] = a
sz[a] += sz[b]
activeR[a] += activeR[b]
activeB[a] += activeB[b]
if activeR[a] > 0 {
redSet[a] = struct{}{}
}
if activeB[a] > 0 {
blueSet[a] = struct{}{}
}
components--
return a
}
exp := 0
for _, id := range byL {
l := segs[id].l
for exp < n && segs[byR[exp]].r < l {
x := byR[exp]
root := find(x)
if segs[x].c == 0 {
activeR[root]--
if activeR[root] == 0 {
delete(redSet, root)
}
} else {
activeB[root]--
if activeB[root] == 0 {
delete(blueSet, root)
}
}
exp++
}
components++
if segs[id].c == 0 {
activeR[id] = 1
redSet[id] = struct{}{}
roots := make([]int, 0, len(blueSet))
for rt := range blueSet {
roots = append(roots, rt)
}
base := id
for _, rt := range roots {
base = unite(base, rt)
}
} else {
activeB[id] = 1
blueSet[id] = struct{}{}
roots := make([]int, 0, len(redSet))
for rt := range redSet {
roots = append(roots, rt)
}
base := id
for _, rt := range roots {
base = unite(base, rt)
}
}
}
out.WriteString(strconv.Itoa(components))
out.WriteByte('\n')
}
os.Stdout.WriteString(out.String())
}