#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=6e6+10; #define int long long int e[N],h[N],ne[N],w[N]; int idx; int k; inline int read() { int num=0, w=0; char ch=0; while (!isdigit(ch)) { w|=ch=='-'; ch = getchar(); } while (isdigit(ch)) { num = (num<<3) + (num<<1) + (ch^48); ch = getchar(); } return w? -num: num; } void add(int a,int b,int c) { e[idx]=b; w[idx]=c; ne[idx]=h[a]; h[a]=idx++; } int dfs(int u,int fa,int &ans1,int &ans2) { int cnt=0; for(int i=h[u]; i!=-1; i=ne[i]) { int v=e[i]; if(v==fa) continue; int val=w[i]; int t=dfs(v,u,ans1,ans2); cnt+=t; //对于最小值,肯定是 能不经过 就不经过,如果连接这条边的两个子树的size 都是 偶数 //那么就 可以在子树中匹配,不用经过这条边 //如果是 存在奇数,那么就必然存在一对点,要经过这条边 if(t&1) ans1+=val; //对于最大值,肯定希望,多次利用, //然后就看,被这条边分割成的两个子树的大小,最多有min(2*k-t,t) 对点, //所以最多经过min(2*k-t,t)次 ans2+=min(2*k-t,t)*val; } return cnt+1; } void solve() { idx=0; k=read(); for(int i=0;i<=2*k;i++) h[i]=-1; for(int i=1; i<=2*k-1; i++) { int a=read(),b=read(),c=read(); add(a,b,c); add(b,a,c); } int ans1=0; int ans2=0; dfs(1,0,ans1,ans2); cout<<ans1<<" "<<ans2<<endl; } signed main() { int t=read(); while(t--) solve(); }