#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const ll mod = 1e9 + 7;
//const ll mod = 998244353;
#define REP(i,n) for(int i=0;i<(int)n;++i)
//debug
#define dump(x)  cerr << #x << " = " << (x) << endl;
#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl;
template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
template<class S, class T> ostream& operator << (ostream& os, const pair<S, T> v){
os << "(" << v.first << ", " << v.second << ")"; return os;
}
template<class T> ostream& operator << (ostream& os, const vector<T> v){
for(int i = 0; i < (int)v.size(); i++){if(i > 0){os << " ";} os << v[i];} return os;
}
template<class T> ostream& operator << (ostream& os, const vector<vector<T>> v){
for(int i = 0; i < (int)v.size(); i++){if(i > 0){os << endl;} os << v[i];} return os;
}
string num2bit(ll num, ll len){
    string bit = "";
    REP(i, len){
    bit += char('0'+(num>>i & 1));
    }
    return bit;
}

using Graph = vector<vector<int>>;
ll n;

pll dfs(ll now, ll par, Graph &G){
	pll res = {0, now};
	for(auto next: G[now]){
		if(next == par) continue;
		auto cost = dfs(next, now, G);
		cost.first++;
		res = max(res, cost);
	}
	return res;
}

pair<pll, pll> tree_diameter(Graph &G){
	auto p = dfs(0, -1, G);
	auto q = dfs(p.second, -1, G);
	// (p.second, q.second) is the diameter
	return {p, q};
}

bool get_diameter_vertices(Graph &G, ll now, ll par, ll v, vector<ll> &path){
    if(now == v){
        path.push_back(now);
        return true;
    }

    bool ok = false;
    for(auto next: G[now]){
        if(next == par) continue;
        bool flag = get_diameter_vertices(G, next, now, v, path);
        if(flag) ok = true;
    }
    if(ok) path.push_back(now);
    return ok;
}

void dfs2(ll now, ll par, ll d, const Graph &G, vector<ll> &dist){
    chmin(dist[now], d);
    for(auto next: G[now]){
        if(next == par) continue;
        dfs2(next, now, d+1, G, dist);
    }
    return;
}

const ll INF = (1ll<<60);

ll solve(ll v1, ll v2, const Graph &G){
    vector<ll> dist(n, INF);
    if(v1==v2){
        dfs2(v1, -1, 0, G, dist);
    }else{
        dfs2(v1, -1, 1, G, dist);
        dfs2(v2, -1, 1, G, dist);
    }

    ll D = -1;
    REP(i, n) chmax(D, dist[i]);
    vector<vector<ll>> V(D+1);
    REP(i, n){
        V[dist[i]].push_back(i);
    }

    vector<ll> kazu(n, 0);
    REP(j, V[D].size()){
        kazu[V[D][j]] = 1;
    }

    for(int i=D-1;i>=0;i--){
        REP(j, V[i+1].size()){
            ll ver = V[i+1][j];
            REP(k, G[ver].size()){
                ll next = G[ver][k];
                if(dist[next] == dist[ver]-1){
                    kazu[next] += kazu[ver];
                }
            }
        }            

        ll ma = 0;
        REP(j, V[i].size()){
            chmax(ma, kazu[V[i][j]]);
        }
        REP(j, V[i].size()){
            kazu[V[i][j]] = ma;
        }
    }

    ll res = 0;
    for(auto v: V[1]) res += kazu[v];
    return res;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);

    cin >> n;
    Graph G(n);
    REP(i, n-1){
        int a, b;
        cin >> a >> b;
        a--, b--;
        G[a].push_back(b);
        G[b].push_back(a);
    }

    auto r = tree_diameter(G);
    auto p = r.first;
    auto q = r.second;
    ll d = q.first;
    ll u = p.second;
    ll v = q.second;

    vector<ll> path;
    get_diameter_vertices(G, u, -1, v, path);

    ll ans1, ans2 = INF;
    
    ans1 = d/2 + 1;

    if(d%2){
        chmin(ans2, solve(path[d/2], path[d/2+1], G));
    }else{
        ll center = path[d/2];
        chmin(ans2, solve(center, center, G));
        for(auto v: G[center]){
            chmin(ans2, solve(center, v, G));
        }
    } 

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

Measured memory_bytes: 256