#include <bits/stdc++.h>
using namespace std;
int t, k, a, b, w;
vector<pair<long long, long long> > adj[600001];
vector<int> levelorder;
int par[600001];
queue<int> q;
bool vis[600001];
unordered_map<long long, int> weights;
int subtreesz[600001];
int h[600001];
vector<pair<int, int> > edgelist;
void get_level_order() {
  for (int i = 1; i <= 2 * k; i++) vis[i] = false;
  q.push(1);
  vis[1] = true;
  while (!q.empty()) {
    int cur = q.front();
    levelorder.push_back(cur);
    q.pop();
    for (int i = 0; i < adj[cur].size(); i++) {
      if (!vis[adj[cur][i].first]) {
        vis[adj[cur][i].first] = true;
        par[adj[cur][i].first] = cur;
        q.push(adj[cur][i].first);
      }
    }
  }
}
long long rc(long long a, long long b) { return a * (2 * k) + b; }
int get_subsz(int node) {
  vis[node] = true;
  subtreesz[node] = 1;
  for (int i = 0; i < adj[node].size(); i++) {
    if (!vis[adj[node][i].first]) {
      h[adj[node][i].first] = h[node] + 1;
      subtreesz[node] += get_subsz(adj[node][i].first);
    }
  }
  return subtreesz[node];
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cin >> t;
  while (t--) {
    cin >> k;
    for (int i = 0; i <= 2 * k; i++) adj[i].clear();
    edgelist.clear();
    levelorder.clear();
    weights.clear();
    for (int i = 0; i < 2 * k - 1; i++) {
      cin >> a >> b >> w;
      adj[a].emplace_back(b, w);
      adj[b].emplace_back(a, w);
      weights[rc(a, b)] = w;
      weights[rc(b, a)] = w;
      edgelist.emplace_back(a, b);
    }
    get_level_order();
    assert(levelorder.size() == 2 * k);
    for (int i = 0; i <= 2 * k; i++) vis[i] = false;
    long long mincost = 0;
    for (int i = 2 * k - 1; i >= 0; i--) {
      int cur = levelorder[i];
      if (!vis[cur]) {
        assert(i != 0);
        vis[cur] = true;
        int it = i - 1;
        while (vis[levelorder[it]]) {
          it--;
          assert(it >= 0);
        }
        if (par[levelorder[it]] == par[cur]) {
          vis[levelorder[it]] = true;
          mincost += weights[rc(cur, par[cur])] +
                     weights[rc(levelorder[it], par[levelorder[it]])];
        } else {
          assert(!vis[par[cur]]);
          mincost += weights[rc(cur, par[cur])];
          vis[par[cur]] = true;
        }
      }
    }
    long long maxcost = 0;
    for (int i = 0; i <= 2 * k; i++) vis[i] = false;
    get_subsz(1);
    for (int i = 0; i < 2 * k - 1; i++) {
      int n1 = edgelist[i].first;
      int n2 = edgelist[i].second;
      if (h[n1] > h[n2]) swap(n1, n2);
      maxcost += weights[rc(n1, n2)] *
                 (long long)(min(subtreesz[n2], 2 * k - subtreesz[n2]));
    }
    cout << mincost << ' ' << maxcost << endl;
  }
}
