#include<iostream>
#include<cstdio>
using namespace std;
const int inf=214748364;
int f[100010][2],opt[100010],goal[100010];
struct node{
int c1,c2;
}dp[100010][2],tool;
int n,tot,ver[200010],head[100010],edge[200010],edge1[200010],Next[200010];
void add(int x,int y,int z,int w){
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
edge[tot]=z;
edge1[tot]=w;
}
node work(node a,node b,node c,node d){
node e;
if(a.c1+b.c1<c.c1+d.c1){
e.c1=a.c1+b.c1;
e.c2=a.c2+b.c2;
}
else if(a.c1+b.c1==c.c1+d.c1){
if(a.c2+b.c2<c.c2+d.c2){
e.c1=a.c1+b.c1;
e.c2=a.c2+b.c2;
}
else{
e.c1=c.c1+d.c1;
e.c2=c.c2+d.c2;
}
}
else{
e.c1=c.c1+d.c1;
e.c2=c.c2+d.c2;
}
return e;
}
void dfs(int x,int fa){
node w1,w2;
w1.c1=w1.c2=inf;
w2.c1=w2.c2=0;
for(int i=head[x];i;i=Next[i]){
int y=ver[i];
if(y==fa)continue;
opt[y]=edge[i];
goal[y]=edge1[i];
dfs(y,x);
node w11=w1;
w1=work(dp[y][0],w1,dp[y][1],w2);
w2=work(dp[y][1],w11,dp[y][0],w2);
}
if(goal[x]==2){
w2.c1++;
w1.c2++;
w2.c2++;
dp[x][1]=work(w1,tool,w2,tool);
w2.c1--;
w1.c2--;
w2.c2--;
w1.c1++;
dp[x][0]=work(w1,tool,w2,tool);
}
else{
if(opt[x]!=goal[x]){
dp[x][0].c1=inf,dp[x][0].c2=inf;
w2.c1++;
w1.c2++;
w2.c2++;
dp[x][1]=work(w1,tool,w2,tool);
}
else{
dp[x][1].c1=inf,dp[x][1].c2=inf;
w1.c1++;
dp[x][0]=work(w1,tool,w2,tool);
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1,x,y,z,w;i<n;i++){
scanf("%d%d%d%d",&x,&y,&z,&w);
add(x,y,z,w),add(y,x,z,w);
}
dfs(1,0);
printf("%d %d\n",dp[1][0].c1/2,dp[1][0].c2);
return 0;
}