#include <bits/stdc++.h>

using namespace std;

#define DIM 200009
#define INF ((int)1e18+9ll)
#define pairll pair<int,int>
#define fi first
#define se second
#define ld long double
#define amen exit(0)
#define endl '\n'
#define fast ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MODULO 998244353
#define eps 5001

priority_queue<int>s[DIM];

int a[DIM],b[DIM];

int i,j,k,l,n,m,flag,res1,res2;

struct node{
    int num,pos;
};

node combine(node a,node b){
    if(a.num>b.num)return a;
    else return b;
}

node T[DIM*4];

void buildtree(int v,int tl,int tr){
    if(tl==tr){
        T[v]={s[tl].top(),tl};
        return;
    }

    int tm=(tl+tr)/2;

    buildtree(v*2+1,tl,tm);
    buildtree(v*2+2,tm+1,tr);
    T[v]=combine(T[v*2+1],T[v*2+2]);
}

void update(int v,int tl,int tr,int x){
    if(tl>x || x>tr)return;

    if(tl==tr){
        T[v]={s[tl].top(),tl};
        return;
    }

    int tm=(tl+tr)/2;
    update(v*2+1,tl,tm,x);
    update(v*2+2,tm+1,tr,x);
    T[v]=combine(T[v*2+1],T[v*2+2]);
}

node get(int v,int tl,int tr,int L,int R){
    if(tl>R || L>tr)return {-1,-1};

    if(L<=tl && tr<=R)return T[v];

    int tm=(tl+tr)/2;
    return combine(get(v*2+1,tl,tm,L,R),get(v*2+2,tm+1,tr,L,R));
}

priority_queue<int>q;

vector<int>ress;

int main()
{
   // fast;

    int nt;
    scanf("%d",&nt);
    while(nt--){
        scanf("%d",&n);
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));

        for(i=1;i<=n;i++){
            scanf("%d %d",&k,&l);
            a[k]++;
            b[k]+=l;
        }

        while(!q.empty())q.pop();

        for(i=1;i<=n;i++){
            while(!s[i].empty())s[i].pop();
            s[i].push(-1);
        }

        for(i=1;i<=n;i++){
            if(a[i]!=0)s[a[i]].push(b[i]),q.push(a[i]);
        }

        buildtree(0,1,n);

        flag=0;
        res1=0;
        res2=0;

        for(i=n;i>0;i--){
            if(q.empty())break;
            if(q.top()>=i){
                q.pop();
                res1+=i;
               // if(nt==0)cout<<"WTF "<<i<<' '<<res1<<endl;
                node p=get(0,1,n,i,n);
                s[p.pos].pop();
                res2+=min(p.num,i);
                update(0,1,n,p.pos);
            }
        }
        printf("%d %d\n",res1,res2);
    }

    amen;
}
/*
2 0
3 3
4 2
*/


#include <bits/stdc++.h>

using namespace std;

#define DIM 200009
#define INF ((long long)1e18+9ll)
#define pairll pair<long long,long long>
#define fi first
#define se second
#define ld long double
#define fast ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define amen exit(0)
#define endl '\n'

long long i,j,k,l,n,m,mx,mn,r,sz,res,cnt,curr,num;

pairll a[DIM];

map<long long,long long>mp,mpp;

set<long long>nums;

bool cmp(pairll a,pairll b){
    if(a.se!=b.se)return a.se>b.se;
    return a.fi<b.fi;
}

int main()
{
    fast;

    int nt;
    cin>>nt;
    while(nt--){
        cin>>n;
        mp.clear();
        mpp.clear();
        for(i=1;i<=n;i++){
            cin>>k>>l;
            mp[k]++;
            mpp[k]+=l;
        }
        sz=0;
        for(auto to:mp)a[++sz]={to.se,mpp[to.fi]};
        sort(a+1,a+1+sz);
        curr=a[sz].fi-1;
        res=a[sz].fi;
        cnt=a[sz].fi;
       // num=a[sz].se;
        num=0;
        nums.clear();
        nums.insert(a[sz].fi);

        for(i=sz-1;i>0;i--){
            if(curr<0)break;
            if(a[i].fi<=curr){
                curr=a[i].fi-1;
                cnt+=a[i].fi;
                res=max(res,cnt);
                nums.insert(a[i].fi);
            }
            else{
                cnt+=curr;
                res=max(res,cnt);
                nums.insert(curr);
                curr--;
            }
        }

        sort(a+1,a+1+sz,cmp);

        for(i=1;i<=sz;i++){
            if(nums.size()==0)break;
            auto it=nums.end();
            it--;
            num+=min(*it,a[i].se);
            nums.erase(it);
        }
        cout<<res<<' '<<num<<endl;
    }

    amen;
}


#include <bits/stdc++.h>

using namespace std;

#define DIM 300009
#define INF ((long long)1e18+9ll)
#define pairll pair<long long,long long>
#define fi first
#define se second
#define ld long double
#define amen exit(0)
#define endl '\n'
#define fast ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MODULO 998244353
#define eps 5001

priority_queue<long long>s[DIM];

long long a[DIM],b[DIM];

long long i,j,k,l,n,m,flag,res1,res2;

struct node{
    long long num,pos;
};

node combine(node a,node b){
    if(a.num>b.num)return a;
    else return b;
}

node T[DIM*4];

void buildtree(long long v,long long tl,long long tr){
    if(tl==tr){
        T[v]={s[tl].top(),tl};
        return;
    }

    long long tm=(tl+tr)/2;

    buildtree(v*2+1,tl,tm);
    buildtree(v*2+2,tm+1,tr);
    T[v]=combine(T[v*2+1],T[v*2+2]);
}

void update(long long v,long long tl,long long tr,long long x){
    if(tl>x || x>tr)return;

    if(tl==tr){
        T[v]={s[tl].top(),tl};
        return;
    }

    long long tm=(tl+tr)/2;
    update(v*2+1,tl,tm,x);
    update(v*2+2,tm+1,tr,x);
    T[v]=combine(T[v*2+1],T[v*2+2]);
}

node get(long long v,long long tl,long long tr,long long L,long long R){
    if(tl>R || L>tr)return {-1,-1};

    if(L<=tl && tr<=R)return T[v];

    long long tm=(tl+tr)/2;
    return combine(get(v*2+1,tl,tm,L,R),get(v*2+2,tm+1,tr,L,R));
}

priority_queue<long long>q;

vector<long long>ress;

int main()
{
    fast;

    int nt;
    cin>>nt;
    while(nt--){
        cin>>n;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));

        for(i=1;i<=n;i++){
            cin>>k>>l;
            a[k]++;
            b[k]+=l;
        }

        while(!q.empty())q.pop();

        for(i=1;i<=n;i++){
            while(!s[i].empty())s[i].pop();
            s[i].push(-1);
        }

        for(i=1;i<=n;i++){
            if(a[i]!=0)s[a[i]].push(b[i]),q.push(a[i]);
        }

        buildtree(0,1,n);

        flag=0;
        res1=0;
        res2=0;

        for(i=n;i>0;i--){
            if(q.empty())break;
            if(q.top()>=i){
                q.pop();
                res1+=i;
               // if(nt==0)cout<<"WTF "<<i<<' '<<res1<<endl;
                node p=get(0,1,n,i,n);
                s[p.pos].pop();
                res2+=min(p.num,i);
                update(0,1,n,p.pos);
            }
        }
        cout<<res1<<' '<<res2<<endl;
    }

    amen;
}
/*
2 0
3 3
4 2
*/


#include <bits/stdc++.h>

using namespace std;

#define DIM 200009
#define INF ((int)1e18+9ll)
#define pairll pair<int,int>
#define fi first
#define se second
#define ld long double
#define amen exit(0)
#define endl '\n'
#define fast ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MODULO 998244353
#define eps 5001

vector<int>s[DIM];

int a[DIM],b[DIM];

int i,j,k,l,n,m,flag,res1,res2;

struct node{
    int num,pos;
};

node combine(node a,node b){
    if(a.num>b.num)return a;
    else return b;
}

node T[DIM*4];

int top(vector<int>&a){
    return a[a.size()-1];
}

void buildtree(int v,int tl,int tr){
    if(tl==tr){
        T[v]={top(s[tl]),tl};
        return;
    }

    int tm=(tl+tr)/2;

    buildtree(v*2+1,tl,tm);
    buildtree(v*2+2,tm+1,tr);
    T[v]=combine(T[v*2+1],T[v*2+2]);
}

void update(int v,int tl,int tr,int x){
    if(tl>x || x>tr)return;

    if(tl==tr){
        T[v]={top(s[tl]),tl};
        return;
    }

    int tm=(tl+tr)/2;
    update(v*2+1,tl,tm,x);
    update(v*2+2,tm+1,tr,x);
    T[v]=combine(T[v*2+1],T[v*2+2]);
}

node get(int v,int tl,int tr,int L,int R){
    if(tl>R || L>tr)return {-1,-1};

    if(L<=tl && tr<=R)return T[v];

    int tm=(tl+tr)/2;
    return combine(get(v*2+1,tl,tm,L,R),get(v*2+2,tm+1,tr,L,R));
}

vector<int>q;

int main()
{
   // fast;

    int nt;
    scanf("%d",&nt);
    while(nt--){
        scanf("%d",&n);

        for(i=1;i<=n;i++)a[i]=b[i]=0;

        for(i=1;i<=n;i++){
            scanf("%d %d",&k,&l);
            a[k]++;
            b[k]+=l;
        }

        q.clear();

        for(i=1;i<=n;i++){
            s[i].clear();
            s[i].push_back(-1);
        }

        for(i=1;i<=n;i++){
            if(a[i]!=0)s[a[i]].push_back(b[i]),q.push_back(a[i]);
        }

        for(i=1;i<=n;i++){
            sort(s[i].begin(),s[i].end());
        }

        sort(q.begin(),q.end());

        buildtree(0,1,n);

        flag=0;
        res1=0;
        res2=0;

        for(i=n;i>0;i--){
            if(q.size()==0)break;
            if(top(q)>=i){
                q.pop_back();
                res1+=i;
               // if(nt==0)cout<<"WTF "<<i<<' '<<res1<<endl;
                node p=get(0,1,n,i,n);
                s[p.pos].pop_back();
                res2+=min(p.num,i);
                update(0,1,n,p.pos);
            }
        }
        printf("%d %d\n",res1,res2);
    }

    amen;
}
/*
2 0
3 3
4 2
*/


#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <set>
using namespace std;

typedef long long ll;
typedef pair <ll, ll> pii;

const ll MAX_N = 2e5 + 10;
ll q, n;
ll cnt[MAX_N];
ll good[MAX_N];
vector <ll> vec[MAX_N];
multiset <ll> st;

int main() {
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> q;
	while (q--) {
		cin >> n;
		for (ll i = 0; i < n; i++) {
			ll tmp, f;
			cin >> tmp >> f;
			tmp--;

			cnt[tmp]++;
			good[tmp] += f;
		}

		if (n == 1) {
			cout << "1 " << good[0] << "\n";
			cnt[0] = 0;
			good[0] = 0;
			continue;
		}

		for (ll i = 0; i < n; i++)
			vec[cnt[i]].push_back(good[i]);

		ll ans = 0, mx = 0;
		for (ll i = n; ~i; i--) {
			for (ll j: vec[i])
				st.insert(j);

			if (!st.size())
				continue;

			ans += i;
			auto it = st.end();
			it--;

			mx += min(i, *it);

			st.erase(it);
		}

		cout << ans << " " << mx << "\n";
		st.clear();
		for (ll i = 0; i <= n; i++) {
			cnt[i] = 0;
			good[i] = 0;
			vec[i].clear();
		}
	}
	return 0;
}


#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <set>
using namespace std;

typedef long long ll;
typedef pair <ll, ll> pii;

const ll MAX_N = 2e5 + 10;
ll q, n;
ll cnt[MAX_N];
ll good[MAX_N];
vector <int> vec[MAX_N];
multiset <int> st;

int main() {
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> q;
	while (q--) {
		cin >> n;
		for (ll i = 0; i < n; i++) {
			ll tmp, f;
			cin >> tmp >> f;
			tmp--;

			cnt[tmp]++;
			good[tmp] += f;
		}

		if (n == 1) {
			cout << "1 " << good[0] << "\n";
			cnt[0] = 0;
			good[0] = 0;
			continue;
		}

		for (int i = 0; i < n; i++)
			vec[cnt[i]].push_back(good[i]);

		ll ans = 0, mx = 0;
		for (int i = n; ~i; i--) {
			for (int j: vec[i])
				st.insert(j);

			if (!st.size())
				continue;

			ans += i;
			auto it = st.end();
			it--;

			mx += min(i, *it);

			st.erase(it);
		}

		cout << ans << " " << mx << "\n";
		st.clear();
		for (ll i = 0; i < n; i++) {
			cnt[i] = 0;
			good[i] = 0;
			vec[i].clear();
		}
	}
	return 0;
}


#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <set>
using namespace std;

typedef long long ll;
typedef pair <ll, ll> pii;

const ll MAX_N = 2e5 + 10;
ll q, n;
ll cnt[MAX_N];
ll bad[MAX_N];
vector <int> vec[MAX_N];
multiset <int> st;

int main() {
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> q;
	while (q--) {
		cin >> n;
		for (ll i = 0; i < n; i++) {
			ll tmp, f;
			cin >> tmp >> f;
			tmp--;

			cnt[tmp]++;
			bad[tmp] += f;
		}

		if (n == 1) {
			cout << "1 " << bad[0] << "\n";
			cnt[0] = 0;
			bad[0] = 0;
			continue;
		}

		for (int i = 0; i < n; i++)
			vec[cnt[i]].push_back(cnt[i] - bad[i]);

		ll ans = 0, mx = 0;
		for (int i = n; ~i; i--) {
			for (int j: vec[i])
				st.insert(j);

			if (!st.size())
				continue;

			ans += i;
			auto it = st.begin();

			mx += max(0, i - *it);

			st.erase(it);
		}

		cout << ans << " " << mx << "\n";
		st.clear();
		for (ll i = 0; i < n; i++) {
			cnt[i] = 0;
			bad[i] = 0;
			vec[i].clear();
		}
	}
	return 0;
}


#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <set>
using namespace std;

typedef long long ll;
typedef pair <ll, ll> pii;

const ll MAX_N = 2e5 + 10;
ll q, n;
ll cnt[MAX_N];
ll bad[MAX_N];
vector <int> vec[MAX_N];
multiset <int> st;

int main() {
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> q;
	while (q--) {
		cin >> n;
		for (ll i = 0; i < n; i++) {
			ll tmp, f;
			cin >> tmp >> f; f = 1 - f;
			tmp--;

			cnt[tmp]++;
			bad[tmp] += f;
		}

		if (n == 1) {
			cout << "1 " << 1 - bad[0] << "\n";
			cnt[0] = 0;
			bad[0] = 0;
			continue;
		}

		for (int i = 0; i < n; i++)
			vec[cnt[i]].push_back(cnt[i] - bad[i]);

		ll ans = 0, mx = 0;
		for (int i = n; ~i; i--) {
			for (int j: vec[i])
				st.insert(j);

			if (!st.size())
				continue;

			ans += i;
			auto it = st.end();
			it--;

			mx += max(0, i - *it);

			st.erase(it);
		}

		cout << ans << " " << ans - mx << "\n";
		st.clear();
		for (ll i = 0; i < n; i++) {
			cnt[i] = 0;
			bad[i] = 0;
			vec[i].clear();
		}
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            int j = i + 1;
            while (j < values.size() && values[j].first >= curr && values[j].second >= F) {
                if (F < values[j].second) {
                    F = min(curr, values[j].second);
                    i = j;
                }
                j++;
            }
            candies += curr;
            fCount += F;
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        multiset<int> result;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            result.insert(values[i].second);
            int j = i + 1;
            while (j < values.size() && curr == values[j].first) {
                result.insert(values[j].second);
                j++;
            }
            candies += curr;
            if (!result.empty()) {
                int maxF = *result.rbegin();
                fCount += min(curr, maxF);
                result.erase(--result.end());
            }
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0;) {
            pair<int, int> v = values[i];
            curr = min(curr, v.first);
            candies += curr;
            int F = min(curr, v.second);
            while (i < n - 1 && curr == values[i + 1].first && F < values[i + 1].second)             {
                F = values[i + 1].second;
                i++;
            }
            fCount += min(curr, values[i].second);
            curr--;
            i++;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        multiset<int> result;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            result.insert(values[i].second);
            int j = i + 1;
            while (j < values.size() && curr == values[j].first) {
                result.insert(values[j].second);
                j++;
            }
            candies += curr;
            if (!result.empty()) {
                int maxF = *result.rbegin();
                fCount += min(curr, maxF);
                result.erase(result.find(maxF));
            }
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0;) {
            pair<int, int> v = values[i];
            curr = min(curr, v.first);
            candies += curr;
            int F = min(curr, v.second);
            while (i < n - 1 && curr == values[i + 1].first && F < values[i + 1].second)             {
                i++;
            }
            fCount += min(curr, values[i].second);
            curr--;
            i++;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            pair<int, int> v = values[i];
            curr = min(curr, v.first);
            candies += curr;
            int F = min(curr, v.second);
            while (i < values.size() - 1 && curr == values[i + 1].first && F < values[i + 1].second)             {
                F = values[i + 1].second;
                i++;
            }

            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            int j = i + 1;
            while (j < values.size() && curr <= values[j].first && F <= values[j].second) {
                if (F < values[j].second) {
                    F = values[j].second;
                    i = j;
                }
                j++;
            }
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            int last = i;
            while (i < values.size() - 1 && curr <= values[i + 1].first && F <= values[i + 1].second) {
                if (F < values[i + 1].second) {
                    F = values[i + 1].second;
                    last = i;
                    break;
                }
                i++;
            }
            i = min(i, last);
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0;) {
            pair<int, int> v = values[i];
            curr = min(curr, v.first);
            candies += curr;
            int F = min(curr, v.second);
            while (i < n - 1 && curr == values[i + 1].first && F < values[i + 1].second) {
                F = values[i + 1].second;
                i++;
            }
            fCount += min(curr, F);
            curr--;
            i++;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            bool advanced = false;
            int j = i;
            while (i < values.size() - 1 && curr <= values[i + 1].first && F <= values[i + 1].second) {
                if (F < values[i + 1].second) {
                    F = values[i + 1].second;
                    advanced = true;
                    break;
                }
                i++;
            }
            if (!advanced) {
                i = j;
            }
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        unordered_map<int, pair<int, int>> freq;
        int a, f;
        for (int i = 0; i < n; i++) {
            cin >> a >> f;
            if (freq.find(a) == freq.end()) {
                freq[a] = {1, f};
            }
            else {
                freq[a].first += 1;
                freq[a].second += f;
            }
        }
        vector<vector<int>> count(n + 1);
        for (auto p : freq) {
            count[p.second.first].push_back(p.second.second);
        }
        int candies = 0;
        int fCount = 0;
        multiset<int> result;
        for (int i = n; i > 0; i--) {
            for (auto c : count[i]) {
                result.insert(c);
            }
            if (!result.empty()) {
                int maxF = *result.rbegin();
                candies += i;
                fCount += min(i, maxF);
                result.erase(result.find(maxF));
            }
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            int last = i;
            while (i < values.size() - 1 && curr <= values[i + 1].first && F <= values[i + 1].second) {
                if (F < values[i + 1].second) {
                    F = values[i + 1].second;
                    last = i;
                    break;
                }
                i++;
            }
            i = last;
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        int lastVisited = -1;
        multiset<int> result;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            result.insert(values[i].second);
            int j = i + 1;
            while (j < values.size() && curr != lastVisited && curr == values[j].first) {
                result.insert(values[j].second);
                j++;
            }
            lastVisited = curr;
            candies += curr;
            if (!result.empty()) {
                int maxF = *result.rbegin();
                fCount += min(curr, maxF);
                result.erase(result.find(maxF));
            }
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            int F = min(curr, values[i].second);
            while (i < values.size() - 1 && curr <= values[i + 1].first && F < values[i + 1].second) {
                F = values[i + 1].second;
                i++;
            }
            curr = min(curr, values[i].first);
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            int F = min(curr, values[i].second);
            int j = i + 1;
            while (j < values.size() && values[j].first >= curr && values[j].second >= F) {
                if (F < values[j].second) {
                    F = values[j].second;
                    i = j;
                }
                j++;
            }
            curr = min(curr, values[i].first);
            F = min(curr, values[i].second);
            candies += curr;
            fCount += F;
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            bool advanced = false;
            int j = i;
            while (i < values.size() - 1 && curr <= values[i + 1].first && F <= values[i + 1].second) {
                if (F < values[i + 1].second) {
                    F = values[i + 1].second;
                    advanced = true;
                }
                i++;
            }
            if (!advanced) {
                i = j;
            }
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            int last = i;
            while (i < values.size() - 1 && curr <= values[i + 1].first && F <= values[i + 1].second) {
                if (F < values[i + 1].second) {
                    F = values[i + 1].second;
                    last = i;
                }
                i++;
            }
            i = last;
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            int F = min(curr, values[i].second);
            int j = i + 1;
            while (j < values.size() && values[j].first >= curr && values[j].second >= F) {
                if (F < values[j].second) {
                    F = min(curr, values[j].second);
                    i = j;
                }
                j++;
            }
            curr = min(curr, values[i].first);
            candies += curr;
            fCount += F;
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            int last = i;
            while (i < values.size() - 1 && curr <= values[i + 1].first && F <= values[i + 1].second) {
                if (F < values[i + 1].second) {
                    F = values[i + 1].second;
                    last = i + 1;
                }
                i++;
            }
            i = last;
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        multiset<int> result;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            result.insert(values[i].second);
            int j = i + 1;
            while (j < values.size() && curr == values[j].first) {
                result.insert(values[j].second);
                j++;
            }
            candies += curr;
            if (!result.empty()) {
                int maxF = *result.rbegin();
                fCount += min(curr, maxF);
                result.erase(maxF);
            }
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            int last = i;
            while (i < values.size() - 1 && curr <= values[i + 1].first && F <= values[i + 1].second) {
                if (F < values[i + 1].second) {
                    F = values[i + 1].second;
                    last = i;
                }
                i++;
            }
            i = min(i, last);
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            while (i < values.size() - 1 && curr <= values[i + 1].first && F < values[i + 1].second) {
                F = values[i + 1].second;
                i++;
            }
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        vector<int> arr(n);
        vector<int> f(n);
        unordered_map<int, pair<int, int>> freq;
        for (int i = 0; i < n; i++) {
            cin >> arr[i] >> f[i];
            if (freq.find(arr[i]) == freq.end()) {
                freq[arr[i]] = {1, f[i]};
            }
            else {
                freq[arr[i]].first += 1;
                freq[arr[i]].second += f[i];
            }
        }
        vector<pair<int, int>> values;
        values.reserve(freq.size());
        for (auto p : freq) {
            values.push_back(p.second);
        }
        sort(values.begin(), values.end(), greater<>());
        int candies = 0;
        int fCount = 0;
        int curr = values[0].first;
        for (int i = 0; i < values.size() && curr > 0; i++) {
            curr = min(curr, values[i].first);
            int F = min(curr, values[i].second);
            bool advanced = false;
            int j = i;
            while (i < values.size() - 1 && curr <= values[i + 1].first && F <= values[i + 1].second) {
                if (F < values[i + 1].second) {
                    F = values[i + 1].second;
                    advanced = true;
                    i++;
                    break;
                }
                i++;
            }
            if (!advanced) {
                i = j;
            }
            candies += curr;
            fCount += min(curr, F);
            curr--;
        }
        cout << candies << " " << fCount << endl;
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define mod 1000000007 //998244353
#include<string.h>
#define inf 1000000000000000000
#define maxn 200002
typedef pair<ll,ll> pll;
typedef pair<int,int> pint;
#define endl '\n'
#define mapint_iterator map<int,int> :: iterator
#define mapll_iterator map<ll,ll> :: iterator
#define setint_iterator set<int> :: iterator
#define setll_iterator set<ll> :: iterator
#define setpint_iterator set<pint> :: iterator
#define setpll_iterator set<pll> :: iterator
#define trace(x) cout<<#x<<": "<<x<<" "<<endl
#define trace2(x,y) cout<<#x<<": "<<x<<" | "<<#y<<": "<<y<<endl
#define trace3(x,y,z) cout<<#x<<":" <<x<<" | "<<#y<<": "<<y<<" | "<<#z<<": "<<z<<endl
#define trace4(a,b,c,d) cout<<#a<<": "<<a<<" | "<<#b<<": "<<b<<" | "<<#c<<": "<<c<<" | "<<#d<<": "<<d<<endl
#define cout1(a) cout<<a<<endl
#define cout2(a,b) cout<<a<<" "<<b<<endl
#define cout3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl
#define cout4(a,b,c,d) cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl
#define vcout(v,i) cout<<v[i].fi<<" "<<v[i].se<<endl
typedef priority_queue<ll,vector<ll>,greater<ll> > pqset;
typedef priority_queue<pint,vector<pint>,greater<pint> > pqset_ll;
#define pb push_back
#define fi first
#define se second
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> os;
typedef tree<pll,null_type,less<pll>,rb_tree_tag,tree_order_statistics_node_update> os_pair;
#define mp make_pair
#define acc (ios::sync_with_stdio(false),cin.tie(0))
#define rep(i,n) for(ll i=0;i<n;i++)
#define per(i,n) for(ll i=n-1;i>=0;i--)
#define rep1(i,n) for(ll i=1;i<=n;i++)
#define per1(i,n) for(ll i=n;i>0;i--)
#define repeat(i,start,n) for(ll i=start;i<n;i++)
#define print(a,n) for(ll i=0;i<n;i++){ cout<<a[i]<<" ";}
ll ll_max(ll a,ll b,ll c){return max(a,max(b,c));}
int int_max(int a,int b,int c){return max(a,max(b,c));}
ll ll_min(ll a,ll b,ll c){return min(a,min(b,c));}
int int_min(int a,int b,int c){return min(a,min(b,c));}
ll max(int a,ll b){ return max((ll)a,b);}
ll min(int a,ll b){ return min((ll)a,b);}
ll min(ll a,int b){ return min(a,(ll)b);}
ll max(ll a,int b){ return max(a,(ll)b);}
bool prime[maxn];
ll fact[maxn];
ll Tree[maxn];
pll Tree1[maxn];
ll dx[]={0,0,1,-1};
ll dy[]={1,-1,0,0};
struct Tnode{ long long sum, maxprefix, maxsuffix, maxsum; } T[4*maxn];
Tnode combine(Tnode &node1, Tnode &node2){
    Tnode resnode;
    resnode.sum = node1.sum + node2.sum;
    resnode.maxprefix = max(node1.maxprefix, node1.sum + node2.maxprefix);
    resnode.maxsuffix = max(node1.maxsuffix + node2.sum, node2.maxsuffix);
    resnode.maxsum = max((node1.maxsuffix + node2.maxprefix), max(node1.maxsum , node2.maxsum));
    return resnode;
}
void BuildTree(int v,int tl,int tr,ll a[]){
    if(tl==tr){
        T[v] = { a[tl], a[tl], a[tl], a[tl] }; //???????? ? ?????? ????????
        return;
    }
    int tm = (tl+tr)/2;
    BuildTree(2*v+1, tl, tm,a);
    BuildTree(2*v+2, tm+1, tr,a);
    T[v] = combine(T[2*v+1],T[2*v+2]);
}
void modify(int v, int tl, int tr, int x, ll val,ll a[]) {
    if(x < tl || tr < x) return;
    if(tl==tr){
        T[v]={ val, val, val, val };
        return;
    }
    int tm=(tl+tr)/2;
    modify(2*v+1, tl, tm, x, val,a);
    modify(2*v+2, tm+1, tr, x, val,a);
    T[v] = combine(T[2*v+1],T[2*v+2]);
}
Tnode getquery(int v,int tl,int tr,int L,int R) {
    if(R < tl || tr < L||L>R) return {0,-inf,-inf,-inf};
    if(L <= tl && tr <= R) {
        return T[v];
    }
    int tm = (tl+tr)/2;
    Tnode node1 = getquery(2*v+1, tl, tm, L, R);
    Tnode node2 = getquery(2*v+2, tm+1, tr, L, R);
    return combine(node1, node2);
}
void build_max(int node,int start,int end,ll a[]){
	if(start==end){
		Tree[node]=a[start];
		return;
	}
	int mid=((start+end)>>1);
	build_max(2*node+1,start,mid,a);
	build_max(2*node+2,mid+1,end,a);
	//According to the question,change from here
	Tree[node]=max(Tree[2*node+1],Tree[2*node+2]);
}
void update_max(int node,int start,int end,ll a[],int i,ll val){
	if(start==end){
		Tree[node]=val;
		return;
	}
	int mid=((start+end)>>1);
	if(i<=mid)
		update_max(2*node+1,start,mid,a,i,val);
	else
		update_max(2*node+2,mid+1,end,a,i,val);
	//According to the question,change from here
	Tree[node]=max(Tree[2*node+1],Tree[2*node+2]);
}
ll query_max(int node,int start,int end,int l,int r){
	if(start>end||end<l||start>r)
		return 0;//0 in case of sum , high value in case of min , low value in case of max and soooo on
	if(start>=l&&end<=r)
		return(Tree[node]);
	int mid = (start+end)/2 ;
	ll p1 = query_max(node*2+1, start, mid, l,r);
	ll p2 = query_max(node*2+2, mid+1, end , l,r);
	return max(p1,p2);
}
void build_min(int node,int start,int end,ll a[]){
	if(start==end){
		Tree1[node]={a[start],start};
		return;
	}
	int mid=((start+end)>>1);
	build_min(2*node+1,start,mid,a);
	build_min(2*node+2,mid+1,end,a);
	//According to the question,change from here
	Tree1[node]=min(Tree1[2*node+1],Tree1[2*node+2]);
}
void update_min(int node,int start,int end,ll a[],int i,ll val){
	if(start==end){
		Tree1[node]={val,i};
		return;
	}
	int mid=((start+end)>>1);
	if(i<=mid)
		update_min(2*node+1,start,mid,a,i,val);
	else
		update_min(2*node+2,mid+1,end,a,i,val);
	//According to the question,change from here
	Tree1[node]=min(Tree1[2*node+1],Tree1[2*node+2]);
}
pll query_min(int node,int start,int end,int l,int r){
	if(start>end||end<l||start>r)
		return {1e9,1e9};//0 in case of sum , high value in case of min , low value in case of max and soooo on
	if(start>=l&&end<=r)
		return(Tree1[node]);
	int mid = (start+end)/2 ;
	pll p1 = query_min(node*2+1, start, mid, l,r);
	pll p2 = query_min(node*2+2, mid+1, end , l,r);
	return min(p1,p2);
}
void dfs_connected(int i,vector<int> v[],bool visited[],vector<int> &v3){
	visited[i]=true;
	v3.pb(i);
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_connected(v[i][j],v,visited,v3);
		}
	}
}
void dfs_connected1(int i,vector<int> v[],bool visited[],stack<int> &s){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_connected1(v[i][j],v,visited,s);
		}
	}
	s.push(i);
}
void StronglyConnectedComponents(vector<int> v[],vector<int> v1[],vector<vector<int> > &v2,int n){
	stack<int> s;
	bool visited1[n+1]={false};
	repeat(i,1,n+1){
		if(visited1[i]==false)
			dfs_connected1(i,v,visited1,s);
	}
	bool visited[n+1]={0};
	while(!s.empty()){
		while(visited[s.top()]){
			s.pop();
			if(s.size()==0)
				return;
		}
		int a=s.top();
		s.pop();
		vector<int> v3;
		dfs_connected(a,v1,visited,v3);
		v2.pb(v3);
	}
}
void sieve(ll n){
    memset(prime,true,sizeof(prime));
	prime[1]=false;
    for (ll p=2;p*p<=n;p++){
        if (prime[p]){
            for (ll i=p*p;i<=n;i+=p)
                prime[i]=false;
        }
    }
}
ll phi(ll n){
	ll result=n;
	for(ll i=2;i*i<=n;i++){
		if(n%i==0){
			while(n%i==0)
				n/=i;
			result-=(result)/i;
		}
	}
	if(n>1)
		result-=result/n;
	return result;
}
bool compare_string(pair<string,int> a,pair<string,int> b){
	if(a.fi.size()<b.fi.size())
		return true;
	else if(a.fi.size()==b.fi.size()){
		if(a.fi<b.fi)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool compare_string1(string a,string b){
	if(a.size()<b.size())
		return true;
	else if(a.size()==b.size()){
		if(a<b)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool compare(pair<ll,ll> a,pair<ll,ll> b){
	if(a.first<b.first)
		return true;
	else if(a.first==b.first){
		if(a.se>b.se)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool sortbysec(const pair<int,int> &a,const pair<int,int> &b){
	if(a.se==b.se)
		return a.fi<b.fi;
    return (a.second<b.second);
}
ll power(ll a,ll b){
	if(a==1)
		return 1;
	if(b==0)
		return 1;
	ll c=power(a,b/2);
	ll res=1;
	if(b%2){
		res=(c*c)%mod;
		res*=a;
		res%=mod;
	}
	else
		res=((c*c)%mod);
	return res;
}
ll pow(int a,int b){
	if(a==1)
		return 1;
	if(b==0)
		return 1;
	ll c=pow(a,b/2);
	ll res=1;
	if(b%2){
		res=(c*c);
		res*=(ll)a;
	}
	else
		res=((c*c));
	return res;
}
void dfs_topological(int i,vector<int> v[],bool visited[],int finish[],int &t){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_topological(v[i][j],v,visited,finish,++t);
		}
	}
	finish[i]=(++t);
}
void topologicalSort(vector<int> v[],stack<int> &s,int n){
	int finish[n+1]={0};
	int t=0;
	bool visited[n+1]={0};
	repeat(i,1,n+1){
		if(visited[i]==false)
			dfs_topological(i,v,visited,finish,t);
	}
	vector<pint> v1;
	repeat(i,1,n+1)
		v1.pb({finish[i],i});
	sort(v1.begin(),v1.end());
	rep(i,v1.size())
		s.push(v1[i].se);
}
void bfs(vector<int> v[],int o,int n,int dp[]){
	queue<int> q;
	q.push(o);
	dp[o]=0;
	bool visited[n+1]={0};
	visited[o]=true;
	while(q.empty()==false){
		int a=q.front();
		q.pop();
		for(int i=0;i<v[a].size();i++){
			if(visited[v[a][i]]==false){
				visited[v[a][i]]=true;
				q.push(v[a][i]);
				dp[v[a][i]]=dp[a]+1;
			}
		}
	}
}
void multi_bfs(vector<int> v[],vector<int> v1,int n,int dp[]){
	queue<int> q;
	bool visited[n+1]={0};
	rep(i,v1.size()){
		q.push(v1[i]);
		dp[v1[i]]=0;
		visited[v1[i]]=true;
	}
	while(q.empty()==false){
		int a=q.front();
		q.pop();
		for(int i=0;i<v[a].size();i++){
			if(visited[v[a][i]]==false){
				visited[v[a][i]]=true;
				q.push(v[a][i]);
				dp[v[a][i]]=dp[a]+1;
			}
		}
	}
}
ll modInv(ll a){return power(a,mod-2)%mod;}
ll ncr(ll n,ll r){
	ll b=modInv(fact[n-r]);
	ll c=modInv(fact[r]);
	ll a=fact[n]*b;
	a%=mod;
	a*=c;
	a%=mod;
	return a;
}
int binary_Search(int l,int h){
	int low=l;int high=h;int ans=h;
	while(low <= high){
        int mid = (low+high)/2;
        if(1){
            ans = mid;
            high = mid-1;
        }else low = mid+1;
    }
    return ans;
}
void dfs(int i,vector<int> v[],bool visited[],int dp[],vector<pint> &v3,int u){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false&&dp[v[i][j]]==u){
			visited[v[i][j]]=true;
			v3.pb({min(i,v[i][j]),max(i,v[i][j])});
			dfs(v[i][j],v,visited,dp,v3,u-1);
		}
	}
}
void factorial(ll n){
	fact[0]=1;
	for(ll i=1;i<=n;i++){
		fact[i]=fact[i-1]*i;
		fact[i]%=mod;
	}
}
ll lcm(ll a,ll b){return a*b/__gcd(a,b);}
int find(int x,int a[]){
	if(a[x]==-1)
		return x;
	return find(a[x],a);
}
void insert(int x,int y,int a[],int size[]){
	if(size[x]>=size[y]){
		size[y]+=size[x]+1;
		a[x]=y;
		return;
	}
	size[x]+=size[y]+1;
	a[y]=x;
}
string convert_to_bit(ll a,int bit){
	string s;
	while(a>0){
		s+=(a%2)+48;
		a/=2;
	}
	while(s.size()<bit)
		s+='0';
	reverse(s.begin(),s.end());
	return s;
}
void map_insertrange(pll a1,map<ll,ll> &mp){
	ll a=a1.first;
	mapll_iterator it=mp.upper_bound(a);
	if(it==mp.end())
		mp[a]=a1.se;
	else if(it->fi<=a1.se){
		mp[a]=max(a1.se,it->se);
		mp.erase(it);
	}
	it=mp.lower_bound(a);
	if(it!=mp.begin()){
		it--;
		if(it->se>=a-1){
			mp[it->fi]=mp[a];
			mp.erase(a);
		}
	}
}
bool map_checkrange(ll a,map<ll,ll> &mp){
	mapll_iterator it=mp.upper_bound(a);
	if(it==mp.begin())
		return false;
	it--;
	if(a>=(it->fi)&&a<=(it->se))
		return true;
	return false;
}
//ifstream cin("b_read_on.txt"); ofstream cout("output3.txt");
//Chronology: Binary Search,Greedy,dp
//Use (<<) for multiplication
//Use (>>) for division
// In dp, first try top-down,then bottom-up
//ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);cout<<fixed;cerr.tie(NULL);cout.precision(10);
struct node{
	int cnt1;
	int cnt2;
}a[maxn];
void solve(int countu){
	int n;
	int ans1=0;
	int ans2=0;
	priority_queue<int>pq;
	vector<int>G[maxn];
	cin>>n;
	repeat(i,1,n+1){
		int x;
		int y;
		scanf("%d%d",%x,%y);
		a[x].cnt1++;
		if(y==1)
			a[x].cnt2++;
	}
	repeat(i,1,n+1)
		G[a[i].cnt1].push_back(a[i].cnt2);
	for(int i=n;i>=1;i--){
		for(auto t:G[i])
			pq.push(t);
		if(!pq.empty()){
			ans1+=i;
			ans2+=min(i,pq.top());
			pq.pop();
		}
	}
	printf("%d %d\n",ans1,ans2);
	repeat(i,1,n+1){
	    a[i].cnt1=0;
	    a[i].cnt2=0;
	}
}
int main(){
    int t=1;
	cin>>t;
	int countu=1;
    while(t--){
    	solve(countu);
    	countu++;
    }
}


#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define mod 1000000007 //998244353
#include<string.h>
#define inf 1000000000000000000
#define maxn 200002
typedef pair<ll,ll> pll;
typedef pair<int,int> pint;
#define endl '\n'
#define mapint_iterator map<int,int> :: iterator
#define mapll_iterator map<ll,ll> :: iterator
#define setint_iterator set<int> :: iterator
#define setll_iterator set<ll> :: iterator
#define setpint_iterator set<pint> :: iterator
#define setpll_iterator set<pll> :: iterator
#define trace(x) cout<<#x<<": "<<x<<" "<<endl
#define trace2(x,y) cout<<#x<<": "<<x<<" | "<<#y<<": "<<y<<endl
#define trace3(x,y,z) cout<<#x<<":" <<x<<" | "<<#y<<": "<<y<<" | "<<#z<<": "<<z<<endl
#define trace4(a,b,c,d) cout<<#a<<": "<<a<<" | "<<#b<<": "<<b<<" | "<<#c<<": "<<c<<" | "<<#d<<": "<<d<<endl
#define cout1(a) cout<<a<<endl
#define cout2(a,b) cout<<a<<" "<<b<<endl
#define cout3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl
#define cout4(a,b,c,d) cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl
#define vcout(v,i) cout<<v[i].fi<<" "<<v[i].se<<endl
typedef priority_queue<ll,vector<ll>,greater<ll> > pqset;
typedef priority_queue<pint,vector<pint>,greater<pint> > pqset_ll;
#define pb push_back
#define fi first
#define se second
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> os;
typedef tree<pll,null_type,less<pll>,rb_tree_tag,tree_order_statistics_node_update> os_pair;
#define mp make_pair
#define acc (ios::sync_with_stdio(false),cin.tie(0))
#define rep(i,n) for(ll i=0;i<n;i++)
#define per(i,n) for(ll i=n-1;i>=0;i--)
#define rep1(i,n) for(ll i=1;i<=n;i++)
#define per1(i,n) for(ll i=n;i>0;i--)
#define repeat(i,start,n) for(ll i=start;i<n;i++)
#define print(a,n) for(ll i=0;i<n;i++){ cout<<a[i]<<" ";}
ll ll_max(ll a,ll b,ll c){return max(a,max(b,c));}
int int_max(int a,int b,int c){return max(a,max(b,c));}
ll ll_min(ll a,ll b,ll c){return min(a,min(b,c));}
int int_min(int a,int b,int c){return min(a,min(b,c));}
ll max(int a,ll b){ return max((ll)a,b);}
ll min(int a,ll b){ return min((ll)a,b);}
ll min(ll a,int b){ return min(a,(ll)b);}
ll max(ll a,int b){ return max(a,(ll)b);}
bool prime[maxn];
ll fact[maxn];
ll Tree[maxn];
pll Tree1[maxn];
ll dx[]={0,0,1,-1};
ll dy[]={1,-1,0,0};
struct Tnode{ long long sum, maxprefix, maxsuffix, maxsum; } T[4*maxn];
Tnode combine(Tnode &node1, Tnode &node2){
    Tnode resnode;
    resnode.sum = node1.sum + node2.sum;
    resnode.maxprefix = max(node1.maxprefix, node1.sum + node2.maxprefix);
    resnode.maxsuffix = max(node1.maxsuffix + node2.sum, node2.maxsuffix);
    resnode.maxsum = max((node1.maxsuffix + node2.maxprefix), max(node1.maxsum , node2.maxsum));
    return resnode;
}
void BuildTree(int v,int tl,int tr,ll a[]){
    if(tl==tr){
        T[v] = { a[tl], a[tl], a[tl], a[tl] }; //???????? ? ?????? ????????
        return;
    }
    int tm = (tl+tr)/2;
    BuildTree(2*v+1, tl, tm,a);
    BuildTree(2*v+2, tm+1, tr,a);
    T[v] = combine(T[2*v+1],T[2*v+2]);
}
void modify(int v, int tl, int tr, int x, ll val,ll a[]) {
    if(x < tl || tr < x) return;
    if(tl==tr){
        T[v]={ val, val, val, val };
        return;
    }
    int tm=(tl+tr)/2;
    modify(2*v+1, tl, tm, x, val,a);
    modify(2*v+2, tm+1, tr, x, val,a);
    T[v] = combine(T[2*v+1],T[2*v+2]);
}
Tnode getquery(int v,int tl,int tr,int L,int R) {
    if(R < tl || tr < L||L>R) return {0,-inf,-inf,-inf};
    if(L <= tl && tr <= R) {
        return T[v];
    }
    int tm = (tl+tr)/2;
    Tnode node1 = getquery(2*v+1, tl, tm, L, R);
    Tnode node2 = getquery(2*v+2, tm+1, tr, L, R);
    return combine(node1, node2);
}
void build_max(int node,int start,int end,ll a[]){
	if(start==end){
		Tree[node]=a[start];
		return;
	}
	int mid=((start+end)>>1);
	build_max(2*node+1,start,mid,a);
	build_max(2*node+2,mid+1,end,a);
	//According to the question,change from here
	Tree[node]=max(Tree[2*node+1],Tree[2*node+2]);
}
void update_max(int node,int start,int end,ll a[],int i,ll val){
	if(start==end){
		Tree[node]=val;
		return;
	}
	int mid=((start+end)>>1);
	if(i<=mid)
		update_max(2*node+1,start,mid,a,i,val);
	else
		update_max(2*node+2,mid+1,end,a,i,val);
	//According to the question,change from here
	Tree[node]=max(Tree[2*node+1],Tree[2*node+2]);
}
ll query_max(int node,int start,int end,int l,int r){
	if(start>end||end<l||start>r)
		return 0;//0 in case of sum , high value in case of min , low value in case of max and soooo on
	if(start>=l&&end<=r)
		return(Tree[node]);
	int mid = (start+end)/2 ;
	ll p1 = query_max(node*2+1, start, mid, l,r);
	ll p2 = query_max(node*2+2, mid+1, end , l,r);
	return max(p1,p2);
}
void build_min(int node,int start,int end,ll a[]){
	if(start==end){
		Tree1[node]={a[start],start};
		return;
	}
	int mid=((start+end)>>1);
	build_min(2*node+1,start,mid,a);
	build_min(2*node+2,mid+1,end,a);
	//According to the question,change from here
	Tree1[node]=min(Tree1[2*node+1],Tree1[2*node+2]);
}
void update_min(int node,int start,int end,ll a[],int i,ll val){
	if(start==end){
		Tree1[node]={val,i};
		return;
	}
	int mid=((start+end)>>1);
	if(i<=mid)
		update_min(2*node+1,start,mid,a,i,val);
	else
		update_min(2*node+2,mid+1,end,a,i,val);
	//According to the question,change from here
	Tree1[node]=min(Tree1[2*node+1],Tree1[2*node+2]);
}
pll query_min(int node,int start,int end,int l,int r){
	if(start>end||end<l||start>r)
		return {1e9,1e9};//0 in case of sum , high value in case of min , low value in case of max and soooo on
	if(start>=l&&end<=r)
		return(Tree1[node]);
	int mid = (start+end)/2 ;
	pll p1 = query_min(node*2+1, start, mid, l,r);
	pll p2 = query_min(node*2+2, mid+1, end , l,r);
	return min(p1,p2);
}
void dfs_connected(int i,vector<int> v[],bool visited[],vector<int> &v3){
	visited[i]=true;
	v3.pb(i);
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_connected(v[i][j],v,visited,v3);
		}
	}
}
void dfs_connected1(int i,vector<int> v[],bool visited[],stack<int> &s){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_connected1(v[i][j],v,visited,s);
		}
	}
	s.push(i);
}
void StronglyConnectedComponents(vector<int> v[],vector<int> v1[],vector<vector<int> > &v2,int n){
	stack<int> s;
	bool visited1[n+1]={false};
	repeat(i,1,n+1){
		if(visited1[i]==false)
			dfs_connected1(i,v,visited1,s);
	}
	bool visited[n+1]={0};
	while(!s.empty()){
		while(visited[s.top()]){
			s.pop();
			if(s.size()==0)
				return;
		}
		int a=s.top();
		s.pop();
		vector<int> v3;
		dfs_connected(a,v1,visited,v3);
		v2.pb(v3);
	}
}
void sieve(ll n){
    memset(prime,true,sizeof(prime));
	prime[1]=false;
    for (ll p=2;p*p<=n;p++){
        if (prime[p]){
            for (ll i=p*p;i<=n;i+=p)
                prime[i]=false;
        }
    }
}
ll phi(ll n){
	ll result=n;
	for(ll i=2;i*i<=n;i++){
		if(n%i==0){
			while(n%i==0)
				n/=i;
			result-=(result)/i;
		}
	}
	if(n>1)
		result-=result/n;
	return result;
}
bool compare_string(pair<string,int> a,pair<string,int> b){
	if(a.fi.size()<b.fi.size())
		return true;
	else if(a.fi.size()==b.fi.size()){
		if(a.fi<b.fi)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool compare_string1(string a,string b){
	if(a.size()<b.size())
		return true;
	else if(a.size()==b.size()){
		if(a<b)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool compare(pair<ll,ll> a,pair<ll,ll> b){
	if(a.first<b.first)
		return true;
	else if(a.first==b.first){
		if(a.se>b.se)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool sortbysec(const pair<int,int> &a,const pair<int,int> &b){
	if(a.se==b.se)
		return a.fi<b.fi;
    return (a.second<b.second);
}
ll power(ll a,ll b){
	if(a==1)
		return 1;
	if(b==0)
		return 1;
	ll c=power(a,b/2);
	ll res=1;
	if(b%2){
		res=(c*c)%mod;
		res*=a;
		res%=mod;
	}
	else
		res=((c*c)%mod);
	return res;
}
ll pow(int a,int b){
	if(a==1)
		return 1;
	if(b==0)
		return 1;
	ll c=pow(a,b/2);
	ll res=1;
	if(b%2){
		res=(c*c);
		res*=(ll)a;
	}
	else
		res=((c*c));
	return res;
}
void dfs_topological(int i,vector<int> v[],bool visited[],int finish[],int &t){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_topological(v[i][j],v,visited,finish,++t);
		}
	}
	finish[i]=(++t);
}
void topologicalSort(vector<int> v[],stack<int> &s,int n){
	int finish[n+1]={0};
	int t=0;
	bool visited[n+1]={0};
	repeat(i,1,n+1){
		if(visited[i]==false)
			dfs_topological(i,v,visited,finish,t);
	}
	vector<pint> v1;
	repeat(i,1,n+1)
		v1.pb({finish[i],i});
	sort(v1.begin(),v1.end());
	rep(i,v1.size())
		s.push(v1[i].se);
}
void bfs(vector<int> v[],int o,int n,int dp[]){
	queue<int> q;
	q.push(o);
	dp[o]=0;
	bool visited[n+1]={0};
	visited[o]=true;
	while(q.empty()==false){
		int a=q.front();
		q.pop();
		for(int i=0;i<v[a].size();i++){
			if(visited[v[a][i]]==false){
				visited[v[a][i]]=true;
				q.push(v[a][i]);
				dp[v[a][i]]=dp[a]+1;
			}
		}
	}
}
void multi_bfs(vector<int> v[],vector<int> v1,int n,int dp[]){
	queue<int> q;
	bool visited[n+1]={0};
	rep(i,v1.size()){
		q.push(v1[i]);
		dp[v1[i]]=0;
		visited[v1[i]]=true;
	}
	while(q.empty()==false){
		int a=q.front();
		q.pop();
		for(int i=0;i<v[a].size();i++){
			if(visited[v[a][i]]==false){
				visited[v[a][i]]=true;
				q.push(v[a][i]);
				dp[v[a][i]]=dp[a]+1;
			}
		}
	}
}
ll modInv(ll a){return power(a,mod-2)%mod;}
ll ncr(ll n,ll r){
	ll b=modInv(fact[n-r]);
	ll c=modInv(fact[r]);
	ll a=fact[n]*b;
	a%=mod;
	a*=c;
	a%=mod;
	return a;
}
int binary_Search(int l,int h){
	int low=l;int high=h;int ans=h;
	while(low <= high){
        int mid = (low+high)/2;
        if(1){
            ans = mid;
            high = mid-1;
        }else low = mid+1;
    }
    return ans;
}
void dfs(int i,vector<int> v[],bool visited[],int dp[],vector<pint> &v3,int u){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false&&dp[v[i][j]]==u){
			visited[v[i][j]]=true;
			v3.pb({min(i,v[i][j]),max(i,v[i][j])});
			dfs(v[i][j],v,visited,dp,v3,u-1);
		}
	}
}
void factorial(ll n){
	fact[0]=1;
	for(ll i=1;i<=n;i++){
		fact[i]=fact[i-1]*i;
		fact[i]%=mod;
	}
}
ll lcm(ll a,ll b){return a*b/__gcd(a,b);}
int find(int x,int a[]){
	if(a[x]==-1)
		return x;
	return find(a[x],a);
}
void insert(int x,int y,int a[],int size[]){
	if(size[x]>=size[y]){
		size[y]+=size[x]+1;
		a[x]=y;
		return;
	}
	size[x]+=size[y]+1;
	a[y]=x;
}
string convert_to_bit(ll a,int bit){
	string s;
	while(a>0){
		s+=(a%2)+48;
		a/=2;
	}
	while(s.size()<bit)
		s+='0';
	reverse(s.begin(),s.end());
	return s;
}
void map_insertrange(pll a1,map<ll,ll> &mp){
	ll a=a1.first;
	mapll_iterator it=mp.upper_bound(a);
	if(it==mp.end())
		mp[a]=a1.se;
	else if(it->fi<=a1.se){
		mp[a]=max(a1.se,it->se);
		mp.erase(it);
	}
	it=mp.lower_bound(a);
	if(it!=mp.begin()){
		it--;
		if(it->se>=a-1){
			mp[it->fi]=mp[a];
			mp.erase(a);
		}
	}
}
bool map_checkrange(ll a,map<ll,ll> &mp){
	mapll_iterator it=mp.upper_bound(a);
	if(it==mp.begin())
		return false;
	it--;
	if(a>=(it->fi)&&a<=(it->se))
		return true;
	return false;
}
//ifstream cin("b_read_on.txt"); ofstream cout("output3.txt");
//Chronology: Binary Search,Greedy,dp
//Use (<<) for multiplication
//Use (>>) for division
// In dp, first try top-down,then bottom-up
//ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);cout<<fixed;cerr.tie(NULL);cout.precision(10);
struct node{
	int cnt1;
	int cnt2;
}a[maxn];
void solve(int countu){
	int n;
	int ans1=0;
	int ans2=0;
	priority_queue<int>pq;
	cin>>n;
	vector<int>G[n];
	repeat(i,1,n+1){
		int x;
		int y;
		scanf("%d%d",&x,&y);
		a[x].cnt1++;
		if(y==1)
			a[x].cnt2++;
	}
	repeat(i,1,n+1)
		G[a[i].cnt1].pb(a[i].cnt2);
	for(int i=n;i>=1;i--){
		for(auto t:G[i])
			pq.push(t);
		if(!pq.empty()){
			ans1+=i;
			ans2+=min(i,pq.top());
			pq.pop();
		}
	}
	printf("%d %d\n",ans1,ans2);
	repeat(i,1,n+1){
	    a[i].cnt1=0;
	    a[i].cnt2=0;
	}
}
int main(){
    int t=1;
	cin>>t;
	int countu=1;
    while(t--){
    	solve(countu);
    	countu++;
    }
}


#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define mod 1000000007 //998244353
#include<string.h>
#define inf 1000000000000000000
#define maxn 200002
typedef pair<ll,ll> pll;
typedef pair<int,int> pint;
#define endl '\n'
#define mapint_iterator map<int,int> :: iterator
#define mapll_iterator map<ll,ll> :: iterator
#define setint_iterator set<int> :: iterator
#define setll_iterator set<ll> :: iterator
#define setpint_iterator set<pint> :: iterator
#define setpll_iterator set<pll> :: iterator
#define trace(x) cout<<#x<<": "<<x<<" "<<endl
#define trace2(x,y) cout<<#x<<": "<<x<<" | "<<#y<<": "<<y<<endl
#define trace3(x,y,z) cout<<#x<<":" <<x<<" | "<<#y<<": "<<y<<" | "<<#z<<": "<<z<<endl
#define trace4(a,b,c,d) cout<<#a<<": "<<a<<" | "<<#b<<": "<<b<<" | "<<#c<<": "<<c<<" | "<<#d<<": "<<d<<endl
#define cout1(a) cout<<a<<endl
#define cout2(a,b) cout<<a<<" "<<b<<endl
#define cout3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl
#define cout4(a,b,c,d) cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl
#define vcout(v,i) cout<<v[i].fi<<" "<<v[i].se<<endl
typedef priority_queue<ll,vector<ll>,greater<ll> > pqset;
typedef priority_queue<pint,vector<pint>,greater<pint> > pqset_ll;
#define pb push_back
#define fi first
#define se second
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> os;
typedef tree<pll,null_type,less<pll>,rb_tree_tag,tree_order_statistics_node_update> os_pair;
#define mp make_pair
#define acc (ios::sync_with_stdio(false),cin.tie(0))
#define rep(i,n) for(ll i=0;i<n;i++)
#define per(i,n) for(ll i=n-1;i>=0;i--)
#define rep1(i,n) for(ll i=1;i<=n;i++)
#define per1(i,n) for(ll i=n;i>0;i--)
#define repeat(i,start,n) for(ll i=start;i<n;i++)
#define print(a,n) for(ll i=0;i<n;i++){ cout<<a[i]<<" ";}
ll ll_max(ll a,ll b,ll c){return max(a,max(b,c));}
int int_max(int a,int b,int c){return max(a,max(b,c));}
ll ll_min(ll a,ll b,ll c){return min(a,min(b,c));}
int int_min(int a,int b,int c){return min(a,min(b,c));}
ll max(int a,ll b){ return max((ll)a,b);}
ll min(int a,ll b){ return min((ll)a,b);}
ll min(ll a,int b){ return min(a,(ll)b);}
ll max(ll a,int b){ return max(a,(ll)b);}
bool prime[maxn];
ll fact[maxn];
ll Tree[maxn];
pll Tree1[maxn];
ll dx[]={0,0,1,-1};
ll dy[]={1,-1,0,0};
struct Tnode{ long long sum, maxprefix, maxsuffix, maxsum; } T[4*maxn];
Tnode combine(Tnode &node1, Tnode &node2){
    Tnode resnode;
    resnode.sum = node1.sum + node2.sum;
    resnode.maxprefix = max(node1.maxprefix, node1.sum + node2.maxprefix);
    resnode.maxsuffix = max(node1.maxsuffix + node2.sum, node2.maxsuffix);
    resnode.maxsum = max((node1.maxsuffix + node2.maxprefix), max(node1.maxsum , node2.maxsum));
    return resnode;
}
void BuildTree(int v,int tl,int tr,ll a[]){
    if(tl==tr){
        T[v] = { a[tl], a[tl], a[tl], a[tl] }; //???????? ? ?????? ????????
        return;
    }
    int tm = (tl+tr)/2;
    BuildTree(2*v+1, tl, tm,a);
    BuildTree(2*v+2, tm+1, tr,a);
    T[v] = combine(T[2*v+1],T[2*v+2]);
}
void modify(int v, int tl, int tr, int x, ll val,ll a[]) {
    if(x < tl || tr < x) return;
    if(tl==tr){
        T[v]={ val, val, val, val };
        return;
    }
    int tm=(tl+tr)/2;
    modify(2*v+1, tl, tm, x, val,a);
    modify(2*v+2, tm+1, tr, x, val,a);
    T[v] = combine(T[2*v+1],T[2*v+2]);
}
Tnode getquery(int v,int tl,int tr,int L,int R) {
    if(R < tl || tr < L||L>R) return {0,-inf,-inf,-inf};
    if(L <= tl && tr <= R) {
        return T[v];
    }
    int tm = (tl+tr)/2;
    Tnode node1 = getquery(2*v+1, tl, tm, L, R);
    Tnode node2 = getquery(2*v+2, tm+1, tr, L, R);
    return combine(node1, node2);
}
void build_max(int node,int start,int end,ll a[]){
	if(start==end){
		Tree[node]=a[start];
		return;
	}
	int mid=((start+end)>>1);
	build_max(2*node+1,start,mid,a);
	build_max(2*node+2,mid+1,end,a);
	//According to the question,change from here
	Tree[node]=max(Tree[2*node+1],Tree[2*node+2]);
}
void update_max(int node,int start,int end,ll a[],int i,ll val){
	if(start==end){
		Tree[node]=val;
		return;
	}
	int mid=((start+end)>>1);
	if(i<=mid)
		update_max(2*node+1,start,mid,a,i,val);
	else
		update_max(2*node+2,mid+1,end,a,i,val);
	//According to the question,change from here
	Tree[node]=max(Tree[2*node+1],Tree[2*node+2]);
}
ll query_max(int node,int start,int end,int l,int r){
	if(start>end||end<l||start>r)
		return 0;//0 in case of sum , high value in case of min , low value in case of max and soooo on
	if(start>=l&&end<=r)
		return(Tree[node]);
	int mid = (start+end)/2 ;
	ll p1 = query_max(node*2+1, start, mid, l,r);
	ll p2 = query_max(node*2+2, mid+1, end , l,r);
	return max(p1,p2);
}
void build_min(int node,int start,int end,ll a[]){
	if(start==end){
		Tree1[node]={a[start],start};
		return;
	}
	int mid=((start+end)>>1);
	build_min(2*node+1,start,mid,a);
	build_min(2*node+2,mid+1,end,a);
	//According to the question,change from here
	Tree1[node]=min(Tree1[2*node+1],Tree1[2*node+2]);
}
void update_min(int node,int start,int end,ll a[],int i,ll val){
	if(start==end){
		Tree1[node]={val,i};
		return;
	}
	int mid=((start+end)>>1);
	if(i<=mid)
		update_min(2*node+1,start,mid,a,i,val);
	else
		update_min(2*node+2,mid+1,end,a,i,val);
	//According to the question,change from here
	Tree1[node]=min(Tree1[2*node+1],Tree1[2*node+2]);
}
pll query_min(int node,int start,int end,int l,int r){
	if(start>end||end<l||start>r)
		return {1e9,1e9};//0 in case of sum , high value in case of min , low value in case of max and soooo on
	if(start>=l&&end<=r)
		return(Tree1[node]);
	int mid = (start+end)/2 ;
	pll p1 = query_min(node*2+1, start, mid, l,r);
	pll p2 = query_min(node*2+2, mid+1, end , l,r);
	return min(p1,p2);
}
void dfs_connected(int i,vector<int> v[],bool visited[],vector<int> &v3){
	visited[i]=true;
	v3.pb(i);
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_connected(v[i][j],v,visited,v3);
		}
	}
}
void dfs_connected1(int i,vector<int> v[],bool visited[],stack<int> &s){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_connected1(v[i][j],v,visited,s);
		}
	}
	s.push(i);
}
void StronglyConnectedComponents(vector<int> v[],vector<int> v1[],vector<vector<int> > &v2,int n){
	stack<int> s;
	bool visited1[n+1]={false};
	repeat(i,1,n+1){
		if(visited1[i]==false)
			dfs_connected1(i,v,visited1,s);
	}
	bool visited[n+1]={0};
	while(!s.empty()){
		while(visited[s.top()]){
			s.pop();
			if(s.size()==0)
				return;
		}
		int a=s.top();
		s.pop();
		vector<int> v3;
		dfs_connected(a,v1,visited,v3);
		v2.pb(v3);
	}
}
void sieve(ll n){
    memset(prime,true,sizeof(prime));
	prime[1]=false;
    for (ll p=2;p*p<=n;p++){
        if (prime[p]){
            for (ll i=p*p;i<=n;i+=p)
                prime[i]=false;
        }
    }
}
ll phi(ll n){
	ll result=n;
	for(ll i=2;i*i<=n;i++){
		if(n%i==0){
			while(n%i==0)
				n/=i;
			result-=(result)/i;
		}
	}
	if(n>1)
		result-=result/n;
	return result;
}
bool compare_string(pair<string,int> a,pair<string,int> b){
	if(a.fi.size()<b.fi.size())
		return true;
	else if(a.fi.size()==b.fi.size()){
		if(a.fi<b.fi)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool compare_string1(string a,string b){
	if(a.size()<b.size())
		return true;
	else if(a.size()==b.size()){
		if(a<b)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool compare(pair<ll,ll> a,pair<ll,ll> b){
	if(a.first<b.first)
		return true;
	else if(a.first==b.first){
		if(a.se>b.se)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool sortbysec(const pair<int,int> &a,const pair<int,int> &b){
	if(a.se==b.se)
		return a.fi<b.fi;
    return (a.second<b.second);
}
ll power(ll a,ll b){
	if(a==1)
		return 1;
	if(b==0)
		return 1;
	ll c=power(a,b/2);
	ll res=1;
	if(b%2){
		res=(c*c)%mod;
		res*=a;
		res%=mod;
	}
	else
		res=((c*c)%mod);
	return res;
}
ll pow(int a,int b){
	if(a==1)
		return 1;
	if(b==0)
		return 1;
	ll c=pow(a,b/2);
	ll res=1;
	if(b%2){
		res=(c*c);
		res*=(ll)a;
	}
	else
		res=((c*c));
	return res;
}
void dfs_topological(int i,vector<int> v[],bool visited[],int finish[],int &t){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_topological(v[i][j],v,visited,finish,++t);
		}
	}
	finish[i]=(++t);
}
void topologicalSort(vector<int> v[],stack<int> &s,int n){
	int finish[n+1]={0};
	int t=0;
	bool visited[n+1]={0};
	repeat(i,1,n+1){
		if(visited[i]==false)
			dfs_topological(i,v,visited,finish,t);
	}
	vector<pint> v1;
	repeat(i,1,n+1)
		v1.pb({finish[i],i});
	sort(v1.begin(),v1.end());
	rep(i,v1.size())
		s.push(v1[i].se);
}
void bfs(vector<int> v[],int o,int n,int dp[]){
	queue<int> q;
	q.push(o);
	dp[o]=0;
	bool visited[n+1]={0};
	visited[o]=true;
	while(q.empty()==false){
		int a=q.front();
		q.pop();
		for(int i=0;i<v[a].size();i++){
			if(visited[v[a][i]]==false){
				visited[v[a][i]]=true;
				q.push(v[a][i]);
				dp[v[a][i]]=dp[a]+1;
			}
		}
	}
}
void multi_bfs(vector<int> v[],vector<int> v1,int n,int dp[]){
	queue<int> q;
	bool visited[n+1]={0};
	rep(i,v1.size()){
		q.push(v1[i]);
		dp[v1[i]]=0;
		visited[v1[i]]=true;
	}
	while(q.empty()==false){
		int a=q.front();
		q.pop();
		for(int i=0;i<v[a].size();i++){
			if(visited[v[a][i]]==false){
				visited[v[a][i]]=true;
				q.push(v[a][i]);
				dp[v[a][i]]=dp[a]+1;
			}
		}
	}
}
ll modInv(ll a){return power(a,mod-2)%mod;}
ll ncr(ll n,ll r){
	ll b=modInv(fact[n-r]);
	ll c=modInv(fact[r]);
	ll a=fact[n]*b;
	a%=mod;
	a*=c;
	a%=mod;
	return a;
}
int binary_Search(int l,int h){
	int low=l;int high=h;int ans=h;
	while(low <= high){
        int mid = (low+high)/2;
        if(1){
            ans = mid;
            high = mid-1;
        }else low = mid+1;
    }
    return ans;
}
void dfs(int i,vector<int> v[],bool visited[],int dp[],vector<pint> &v3,int u){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false&&dp[v[i][j]]==u){
			visited[v[i][j]]=true;
			v3.pb({min(i,v[i][j]),max(i,v[i][j])});
			dfs(v[i][j],v,visited,dp,v3,u-1);
		}
	}
}
void factorial(ll n){
	fact[0]=1;
	for(ll i=1;i<=n;i++){
		fact[i]=fact[i-1]*i;
		fact[i]%=mod;
	}
}
ll lcm(ll a,ll b){return a*b/__gcd(a,b);}
int find(int x,int a[]){
	if(a[x]==-1)
		return x;
	return find(a[x],a);
}
void insert(int x,int y,int a[],int size[]){
	if(size[x]>=size[y]){
		size[y]+=size[x]+1;
		a[x]=y;
		return;
	}
	size[x]+=size[y]+1;
	a[y]=x;
}
string convert_to_bit(ll a,int bit){
	string s;
	while(a>0){
		s+=(a%2)+48;
		a/=2;
	}
	while(s.size()<bit)
		s+='0';
	reverse(s.begin(),s.end());
	return s;
}
void map_insertrange(pll a1,map<ll,ll> &mp){
	ll a=a1.first;
	mapll_iterator it=mp.upper_bound(a);
	if(it==mp.end())
		mp[a]=a1.se;
	else if(it->fi<=a1.se){
		mp[a]=max(a1.se,it->se);
		mp.erase(it);
	}
	it=mp.lower_bound(a);
	if(it!=mp.begin()){
		it--;
		if(it->se>=a-1){
			mp[it->fi]=mp[a];
			mp.erase(a);
		}
	}
}
bool map_checkrange(ll a,map<ll,ll> &mp){
	mapll_iterator it=mp.upper_bound(a);
	if(it==mp.begin())
		return false;
	it--;
	if(a>=(it->fi)&&a<=(it->se))
		return true;
	return false;
}
//ifstream cin("b_read_on.txt"); ofstream cout("output3.txt");
//Chronology: Binary Search,Greedy,dp
//Use (<<) for multiplication
//Use (>>) for division
// In dp, first try top-down,then bottom-up
//ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);cout<<fixed;cerr.tie(NULL);cout.precision(10);
struct node{
	int cnt1;
	int cnt2;
}a[maxn];
void solve(int countu){
	int n;
	int ans1=0;
	int ans2=0;
	priority_queue<int>pq;
	vector<int>G[maxn];
	cin>>n;
	repeat(i,1,n+1){
		int x;
		int y;
		scanf("%d%d",&x,&y);
		a[x].cnt1++;
		if(y==1)
			a[x].cnt2++;
	}
	repeat(i,1,n+1)
		G[a[i].cnt1].push_back(a[i].cnt2);
	for(int i=n;i>=1;i--){
		for(auto t:G[i])
			pq.push(t);
		if(!pq.empty()){
			ans1+=i;
			ans2+=min(i,pq.top());
			pq.pop();
		}
	}
	printf("%d %d\n",ans1,ans2);
	repeat(i,1,n+1){
	    a[i].cnt1=0;
	    a[i].cnt2=0;
	}
}
int main(){
    int t=1;
	cin>>t;
	int countu=1;
    while(t--){
    	solve(countu);
    	countu++;
    }
}


#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define mod 1000000007 //998244353
#include<string.h>
#define inf 1000000000000000000
#define maxn 200002
typedef pair<ll,ll> pll;
typedef pair<int,int> pint;
#define endl '\n'
#define mapint_iterator map<int,int> :: iterator
#define mapll_iterator map<ll,ll> :: iterator
#define setint_iterator set<int> :: iterator
#define setll_iterator set<ll> :: iterator
#define setpint_iterator set<pint> :: iterator
#define setpll_iterator set<pll> :: iterator
#define trace(x) cout<<#x<<": "<<x<<" "<<endl
#define trace2(x,y) cout<<#x<<": "<<x<<" | "<<#y<<": "<<y<<endl
#define trace3(x,y,z) cout<<#x<<":" <<x<<" | "<<#y<<": "<<y<<" | "<<#z<<": "<<z<<endl
#define trace4(a,b,c,d) cout<<#a<<": "<<a<<" | "<<#b<<": "<<b<<" | "<<#c<<": "<<c<<" | "<<#d<<": "<<d<<endl
#define cout1(a) cout<<a<<endl
#define cout2(a,b) cout<<a<<" "<<b<<endl
#define cout3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl
#define cout4(a,b,c,d) cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl
#define vcout(v,i) cout<<v[i].fi<<" "<<v[i].se<<endl
typedef priority_queue<ll,vector<ll>,greater<ll> > pqset;
typedef priority_queue<pint,vector<pint>,greater<pint> > pqset_ll;
#define pb push_back
#define fi first
#define se second
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> os;
typedef tree<pll,null_type,less<pll>,rb_tree_tag,tree_order_statistics_node_update> os_pair;
#define mp make_pair
#define acc (ios::sync_with_stdio(false),cin.tie(0))
#define rep(i,n) for(ll i=0;i<n;i++)
#define per(i,n) for(ll i=n-1;i>=0;i--)
#define rep1(i,n) for(ll i=1;i<=n;i++)
#define per1(i,n) for(ll i=n;i>0;i--)
#define repeat(i,start,n) for(ll i=start;i<n;i++)
#define print(a,n) for(ll i=0;i<n;i++){ cout<<a[i]<<" ";}
ll ll_max(ll a,ll b,ll c){return max(a,max(b,c));}
int int_max(int a,int b,int c){return max(a,max(b,c));}
ll ll_min(ll a,ll b,ll c){return min(a,min(b,c));}
int int_min(int a,int b,int c){return min(a,min(b,c));}
ll max(int a,ll b){ return max((ll)a,b);}
ll min(int a,ll b){ return min((ll)a,b);}
ll min(ll a,int b){ return min(a,(ll)b);}
ll max(ll a,int b){ return max(a,(ll)b);}
bool prime[maxn];
ll fact[maxn];
ll Tree[maxn];
pll Tree1[maxn];
ll dx[]={0,0,1,-1};
ll dy[]={1,-1,0,0};
struct Tnode{ long long sum, maxprefix, maxsuffix, maxsum; } T[4*maxn];
Tnode combine(Tnode &node1, Tnode &node2){
    Tnode resnode;
    resnode.sum = node1.sum + node2.sum;
    resnode.maxprefix = max(node1.maxprefix, node1.sum + node2.maxprefix);
    resnode.maxsuffix = max(node1.maxsuffix + node2.sum, node2.maxsuffix);
    resnode.maxsum = max((node1.maxsuffix + node2.maxprefix), max(node1.maxsum , node2.maxsum));
    return resnode;
}
void BuildTree(int v,int tl,int tr,ll a[]){
    if(tl==tr){
        T[v] = { a[tl], a[tl], a[tl], a[tl] }; //???????? ? ?????? ????????
        return;
    }
    int tm = (tl+tr)/2;
    BuildTree(2*v+1, tl, tm,a);
    BuildTree(2*v+2, tm+1, tr,a);
    T[v] = combine(T[2*v+1],T[2*v+2]);
}
void modify(int v, int tl, int tr, int x, ll val,ll a[]) {
    if(x < tl || tr < x) return;
    if(tl==tr){
        T[v]={ val, val, val, val };
        return;
    }
    int tm=(tl+tr)/2;
    modify(2*v+1, tl, tm, x, val,a);
    modify(2*v+2, tm+1, tr, x, val,a);
    T[v] = combine(T[2*v+1],T[2*v+2]);
}
Tnode getquery(int v,int tl,int tr,int L,int R) {
    if(R < tl || tr < L||L>R) return {0,-inf,-inf,-inf};
    if(L <= tl && tr <= R) {
        return T[v];
    }
    int tm = (tl+tr)/2;
    Tnode node1 = getquery(2*v+1, tl, tm, L, R);
    Tnode node2 = getquery(2*v+2, tm+1, tr, L, R);
    return combine(node1, node2);
}
void build_max(int node,int start,int end,ll a[]){
	if(start==end){
		Tree[node]=a[start];
		return;
	}
	int mid=((start+end)>>1);
	build_max(2*node+1,start,mid,a);
	build_max(2*node+2,mid+1,end,a);
	//According to the question,change from here
	Tree[node]=max(Tree[2*node+1],Tree[2*node+2]);
}
void update_max(int node,int start,int end,ll a[],int i,ll val){
	if(start==end){
		Tree[node]=val;
		return;
	}
	int mid=((start+end)>>1);
	if(i<=mid)
		update_max(2*node+1,start,mid,a,i,val);
	else
		update_max(2*node+2,mid+1,end,a,i,val);
	//According to the question,change from here
	Tree[node]=max(Tree[2*node+1],Tree[2*node+2]);
}
ll query_max(int node,int start,int end,int l,int r){
	if(start>end||end<l||start>r)
		return 0;//0 in case of sum , high value in case of min , low value in case of max and soooo on
	if(start>=l&&end<=r)
		return(Tree[node]);
	int mid = (start+end)/2 ;
	ll p1 = query_max(node*2+1, start, mid, l,r);
	ll p2 = query_max(node*2+2, mid+1, end , l,r);
	return max(p1,p2);
}
void build_min(int node,int start,int end,ll a[]){
	if(start==end){
		Tree1[node]={a[start],start};
		return;
	}
	int mid=((start+end)>>1);
	build_min(2*node+1,start,mid,a);
	build_min(2*node+2,mid+1,end,a);
	//According to the question,change from here
	Tree1[node]=min(Tree1[2*node+1],Tree1[2*node+2]);
}
void update_min(int node,int start,int end,ll a[],int i,ll val){
	if(start==end){
		Tree1[node]={val,i};
		return;
	}
	int mid=((start+end)>>1);
	if(i<=mid)
		update_min(2*node+1,start,mid,a,i,val);
	else
		update_min(2*node+2,mid+1,end,a,i,val);
	//According to the question,change from here
	Tree1[node]=min(Tree1[2*node+1],Tree1[2*node+2]);
}
pll query_min(int node,int start,int end,int l,int r){
	if(start>end||end<l||start>r)
		return {1e9,1e9};//0 in case of sum , high value in case of min , low value in case of max and soooo on
	if(start>=l&&end<=r)
		return(Tree1[node]);
	int mid = (start+end)/2 ;
	pll p1 = query_min(node*2+1, start, mid, l,r);
	pll p2 = query_min(node*2+2, mid+1, end , l,r);
	return min(p1,p2);
}
void dfs_connected(int i,vector<int> v[],bool visited[],vector<int> &v3){
	visited[i]=true;
	v3.pb(i);
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_connected(v[i][j],v,visited,v3);
		}
	}
}
void dfs_connected1(int i,vector<int> v[],bool visited[],stack<int> &s){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_connected1(v[i][j],v,visited,s);
		}
	}
	s.push(i);
}
void StronglyConnectedComponents(vector<int> v[],vector<int> v1[],vector<vector<int> > &v2,int n){
	stack<int> s;
	bool visited1[n+1]={false};
	repeat(i,1,n+1){
		if(visited1[i]==false)
			dfs_connected1(i,v,visited1,s);
	}
	bool visited[n+1]={0};
	while(!s.empty()){
		while(visited[s.top()]){
			s.pop();
			if(s.size()==0)
				return;
		}
		int a=s.top();
		s.pop();
		vector<int> v3;
		dfs_connected(a,v1,visited,v3);
		v2.pb(v3);
	}
}
void sieve(ll n){
    memset(prime,true,sizeof(prime));
	prime[1]=false;
    for (ll p=2;p*p<=n;p++){
        if (prime[p]){
            for (ll i=p*p;i<=n;i+=p)
                prime[i]=false;
        }
    }
}
ll phi(ll n){
	ll result=n;
	for(ll i=2;i*i<=n;i++){
		if(n%i==0){
			while(n%i==0)
				n/=i;
			result-=(result)/i;
		}
	}
	if(n>1)
		result-=result/n;
	return result;
}
bool compare_string(pair<string,int> a,pair<string,int> b){
	if(a.fi.size()<b.fi.size())
		return true;
	else if(a.fi.size()==b.fi.size()){
		if(a.fi<b.fi)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool compare_string1(string a,string b){
	if(a.size()<b.size())
		return true;
	else if(a.size()==b.size()){
		if(a<b)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool compare(pair<ll,ll> a,pair<ll,ll> b){
	if(a.first<b.first)
		return true;
	else if(a.first==b.first){
		if(a.se>b.se)
			return true;
		else
			return false;
	}
	else
		return false;
}
bool sortbysec(const pair<int,int> &a,const pair<int,int> &b){
	if(a.se==b.se)
		return a.fi<b.fi;
    return (a.second<b.second);
}
ll power(ll a,ll b){
	if(a==1)
		return 1;
	if(b==0)
		return 1;
	ll c=power(a,b/2);
	ll res=1;
	if(b%2){
		res=(c*c)%mod;
		res*=a;
		res%=mod;
	}
	else
		res=((c*c)%mod);
	return res;
}
ll pow(int a,int b){
	if(a==1)
		return 1;
	if(b==0)
		return 1;
	ll c=pow(a,b/2);
	ll res=1;
	if(b%2){
		res=(c*c);
		res*=(ll)a;
	}
	else
		res=((c*c));
	return res;
}
void dfs_topological(int i,vector<int> v[],bool visited[],int finish[],int &t){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false){
			visited[v[i][j]]=true;
			dfs_topological(v[i][j],v,visited,finish,++t);
		}
	}
	finish[i]=(++t);
}
void topologicalSort(vector<int> v[],stack<int> &s,int n){
	int finish[n+1]={0};
	int t=0;
	bool visited[n+1]={0};
	repeat(i,1,n+1){
		if(visited[i]==false)
			dfs_topological(i,v,visited,finish,t);
	}
	vector<pint> v1;
	repeat(i,1,n+1)
		v1.pb({finish[i],i});
	sort(v1.begin(),v1.end());
	rep(i,v1.size())
		s.push(v1[i].se);
}
void bfs(vector<int> v[],int o,int n,int dp[]){
	queue<int> q;
	q.push(o);
	dp[o]=0;
	bool visited[n+1]={0};
	visited[o]=true;
	while(q.empty()==false){
		int a=q.front();
		q.pop();
		for(int i=0;i<v[a].size();i++){
			if(visited[v[a][i]]==false){
				visited[v[a][i]]=true;
				q.push(v[a][i]);
				dp[v[a][i]]=dp[a]+1;
			}
		}
	}
}
void multi_bfs(vector<int> v[],vector<int> v1,int n,int dp[]){
	queue<int> q;
	bool visited[n+1]={0};
	rep(i,v1.size()){
		q.push(v1[i]);
		dp[v1[i]]=0;
		visited[v1[i]]=true;
	}
	while(q.empty()==false){
		int a=q.front();
		q.pop();
		for(int i=0;i<v[a].size();i++){
			if(visited[v[a][i]]==false){
				visited[v[a][i]]=true;
				q.push(v[a][i]);
				dp[v[a][i]]=dp[a]+1;
			}
		}
	}
}
ll modInv(ll a){return power(a,mod-2)%mod;}
ll ncr(ll n,ll r){
	ll b=modInv(fact[n-r]);
	ll c=modInv(fact[r]);
	ll a=fact[n]*b;
	a%=mod;
	a*=c;
	a%=mod;
	return a;
}
int binary_Search(int l,int h){
	int low=l;int high=h;int ans=h;
	while(low <= high){
        int mid = (low+high)/2;
        if(1){
            ans = mid;
            high = mid-1;
        }else low = mid+1;
    }
    return ans;
}
void dfs(int i,vector<int> v[],bool visited[],int dp[],vector<pint> &v3,int u){
	visited[i]=true;
	rep(j,v[i].size()){
		if(visited[v[i][j]]==false&&dp[v[i][j]]==u){
			visited[v[i][j]]=true;
			v3.pb({min(i,v[i][j]),max(i,v[i][j])});
			dfs(v[i][j],v,visited,dp,v3,u-1);
		}
	}
}
void factorial(ll n){
	fact[0]=1;
	for(ll i=1;i<=n;i++){
		fact[i]=fact[i-1]*i;
		fact[i]%=mod;
	}
}
ll lcm(ll a,ll b){return a*b/__gcd(a,b);}
int find(int x,int a[]){
	if(a[x]==-1)
		return x;
	return find(a[x],a);
}
void insert(int x,int y,int a[],int size[]){
	if(size[x]>=size[y]){
		size[y]+=size[x]+1;
		a[x]=y;
		return;
	}
	size[x]+=size[y]+1;
	a[y]=x;
}
string convert_to_bit(ll a,int bit){
	string s;
	while(a>0){
		s+=(a%2)+48;
		a/=2;
	}
	while(s.size()<bit)
		s+='0';
	reverse(s.begin(),s.end());
	return s;
}
void map_insertrange(pll a1,map<ll,ll> &mp){
	ll a=a1.first;
	mapll_iterator it=mp.upper_bound(a);
	if(it==mp.end())
		mp[a]=a1.se;
	else if(it->fi<=a1.se){
		mp[a]=max(a1.se,it->se);
		mp.erase(it);
	}
	it=mp.lower_bound(a);
	if(it!=mp.begin()){
		it--;
		if(it->se>=a-1){
			mp[it->fi]=mp[a];
			mp.erase(a);
		}
	}
}
bool map_checkrange(ll a,map<ll,ll> &mp){
	mapll_iterator it=mp.upper_bound(a);
	if(it==mp.begin())
		return false;
	it--;
	if(a>=(it->fi)&&a<=(it->se))
		return true;
	return false;
}
//ifstream cin("b_read_on.txt"); ofstream cout("output3.txt");
//Chronology: Binary Search,Greedy,dp
//Use (<<) for multiplication
//Use (>>) for division
// In dp, first try top-down,then bottom-up
//ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);cout<<fixed;cerr.tie(NULL);cout.precision(10);
struct node{
	int cnt1;
	int cnt2;
}a[maxn];
void solve(int countu){
	int n;
	int ans1=0;
	int ans2=0;
	priority_queue<int>pq;
	cin>>n;
	vector<int>G[n+1];
	repeat(i,1,n+1){
		int x;
		int y;
		scanf("%d%d",&x,&y);
		a[x].cnt1++;
		if(y==1)
			a[x].cnt2++;
	}
	repeat(i,1,n+1)
		G[a[i].cnt1].pb(a[i].cnt2);
	for(int i=n;i>=1;i--){
		for(auto t:G[i])
			pq.push(t);
		if(!pq.empty()){
			ans1+=i;
			ans2+=min(i,pq.top());
			pq.pop();
		}
	}
	printf("%d %d\n",ans1,ans2);
	repeat(i,1,n+1){
	    a[i].cnt1=0;
	    a[i].cnt2=0;
	}
}
int main(){
    int t=1;
	cin>>t;
	int countu=1;
    while(t--){
    	solve(countu);
    	countu++;
    }
}


#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp> // Common file
#include <ext/pb_ds/tree_policy.hpp>
#define sz(v)   ((int)(v).size())
#define  all(v)    ((v).begin()),((v).end())
#define  allr(v)    ((v).rbegin()),((v).rend())
#define   pb         push_back
#define   mp         make_pair
#define   mt         make_tuple
//#define   Y            imag()
//#define   X            real()
#define    clr(v,d)      memset( v, d ,sizeof(v))
#define   angle(n)      atan2((n.imag()),(n.real()))
#define   vec(a,b)       ((b)-(a))
//#define   length(a)      hypot( (a.imag()),(a.real()) )
#define   normalize(a)      (a)/(length(a))
//#define    dp(a,b)          (((conj(a))*(b)).real())
//#define    cp(a,b)          (((conj(a))*(b)).imag())
#define    lengthsqrt(a)       dp(a,a)
#define    rotate0( a,ang)    ((a)*exp( point(0,ang) ))
#define    rotateA(about,p,ang)   (rotate0(vec(about,p),ang)+about)
#define    reflection0(m,v)         (conj((v)/(m))*(m))
#define     reflectionA(m,v,p0)     (conj( (vec(p0,v))/(vec(p0,m)) ) * (vec(p0,m)) ) + p0
//#define     same(p1,p2)               ( dp(  vec(p1,p2),vec(p1,p2)) < eps )
#define     PT                    complex<double>
#define outfile freopen("out.out", "w", stdout);
#define infile  freopen("in.in", "r", stdin);
#define PI acos(-1)
typedef  long long     ll ;
typedef  unsigned long long ull;
const double eps= (1e-9);
using namespace std;
using namespace __gnu_pbds;
int dcmp(double a,double b){   return fabs(a-b)<=eps ? 0: (a>b)? 1:-1  ;}
int getBit(int num, int idx) {return ((num >> idx) & 1) == 1;}
ll setBit1(ll num, int idx) {return num | (1ll<<idx);}
ll setBit0(ll num, int idx) {return num & ~(1ll<<idx);}
ll flipBit(int num, int idx) {return num ^ (1<<idx);}
void FS(){ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);}
const int N=200009;
int cnt[N],cnt2[N];
vector<int > v,v1;
vector< pair<int,int> > v2;
priority_queue<int > pq;
void I(int n)
{
    for(int i=0;i<=n;i++)
        cnt[i]=cnt2[i]=0;
    while(!pq.empty())
        pq.pop();
    v1.clear();
    v2.clear();
    v.clear();
}
int main()
{
    int q;
    cin>>q;

    while(q--)
    {
       int n;
       cin>>n;
       int a,b;
       I(n);
       for(int i=0;i<n;i++)
       {
          cin>>a>>b;
          cnt[a]++;
          if(b==1)
            cnt2[a]++;
       }

       for(int i=1;i<=n;i++)
       {
           if(cnt[i]==0)
            continue;
           v.pb(cnt[i]);
           v2.pb(mp(cnt[i],cnt2[i]));
       }
       sort(allr(v2));
       sort(allr(v));
       v1.pb(v[0]);
       ll ans1=v[0],ans2=0;

       for(int i=1;i<sz(v);i++)
       {
           v[i]=max(0,min(v[i],v[i-1]-1));
           ans1+=v[i];
           if(v[i]>0)
           v1.pb(v[i]);
       }
       int id=0;
      // cout<<v[0]<<" "<<v2[id].first<<endl;
       for(int i=0;i<sz(v1);i++)
       {
           while(id<sz(v2)&&v2[id].first>=v1[i])
           {
               pq.push(v2[id].second);
               id++;
           }

           ans2+=min(v1[i],pq.top());
           pq.pop();

       }
       cout<<ans1<<" "<<ans2<<endl;
    }
}