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