package main
import (
"bytes"
"container/heap"
"io"
"os"
"sort"
"strconv"
)
type Pair struct {
c int
g int
}
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] > h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[:n-1]
return x
}
func main() {
data, _ := io.ReadAll(os.Stdin)
idx := 0
nextInt := func() int {
for idx < len(data) && (data[idx] < '0' || data[idx] > '9') {
idx++
}
val := 0
for idx < len(data) && data[idx] >= '0' && data[idx] <= '9' {
val = val*10 + int(data[idx]-'0')
idx++
}
return val
}
q := nextInt()
const maxN = 200000 + 5
cnt := make([]int, maxN)
good := make([]int, maxN)
seen := make([]int, 0)
types := make([]Pair, 0)
var out bytes.Buffer
for qq := 0; qq < q; qq++ {
n := nextInt()
seen = seen[:0]
for i := 0; i < n; i++ {
a := nextInt()
f := nextInt()
if cnt[a] == 0 {
seen = append(seen, a)
}
cnt[a]++
good[a] += f
}
types = types[:0]
for _, a := range seen {
types = append(types, Pair{cnt[a], good[a]})
}
sort.Slice(types, func(i, j int) bool {
return types[i].c > types[j].c
})
total := 0
best := 0
prev := n + 1
p := 0
h := IntHeap{}
for i := 0; i < len(types); i++ {
k := types[i].c
if k >= prev {
k = prev - 1
}
if k <= 0 {
break
}
total += k
prev = k
for p < len(types) && types[p].c >= k {
heap.Push(&h, types[p].g)
p++
}
g := heap.Pop(&h).(int)
if g < k {
best += g
} else {
best += k
}
}
out.WriteString(strconv.Itoa(total))
out.WriteByte(' ')
out.WriteString(strconv.Itoa(best))
if qq+1 < q {
out.WriteByte('\n')
}
for _, a := range seen {
cnt[a] = 0
good[a] = 0
}
}
os.Stdout.Write(out.Bytes())
}