/* 给定一颗2n结点的树,求两个值: 1.给每两个点配对,并且两点之间距离和最小 从叶子结点往上统计,如果子树大小是偶数,那么其到父亲的边权就不用统计,反之要统计 2.给每两个点配对,并且两点之间距离和最大 每条边都被尽可能的访问,一条边将树分成两部分,取小的那部分的size*边权就是这条边的贡献 */ #include<bits/stdc++.h> #include<vector> using namespace std; #define N 300005 #define ll long long ll n; struct Edge{ll to,nxt,w;}e[N<<1]; ll head[N],tot; void add(ll u,ll v,ll w){ e[tot].to=v;e[tot].w=w;e[tot].nxt=head[u];head[u]=tot++; } ll size[N],val[N]; void getsize(int u,int fa){ size[u]=1; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==fa)continue; val[v]=e[i].w; getsize(v,u); size[u]+=size[v]; } } ll ans1,ans2; void dfs1(int u,int fa){ if(size[u]%2)ans1+=val[u]; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==fa)continue; dfs1(v,u); } } void dfs2(int u,int fa){ ll tmp=min(size[u],n-size[u]); ans2+=tmp*val[u]; for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==fa)continue; dfs2(v,u); } } void init(){ memset(head,-1,sizeof head); tot=0; ans1=ans2=0; } int main(){ int t;cin>>t; while(t--){ init(); scanf("%d",&n);n<<=1; for(int i=1;i<=n-1;i++){ ll u,v,w; scanf("%lld%lld%lld",&u,&v,&w); add(u,v,w);add(v,u,w); } getsize(1,1); dfs1(1,1); dfs2(1,1); cout<<ans1<<" "<<ans2<<' '; } }