#include<iostream>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
const int N = 1e5 + 100;
vector<int> edge[N];
vector<int> newedge[N];
stack<int> sta;
int dfn[N], low[N], color[N], cnt, depth, vis[N], in[N], out[N];
void trajan(int u) {
vis[u] = 1;
dfn[u] = ++depth;
low[u] = depth;
sta.push(u);
for (int i = 0; i < edge[u].size(); i++) {
int v = edge[u][i];
if (!dfn[v]) {
trajan(v);
low[u] = min(low[u], low[v]);
}
else if (vis[v]) {
low[u] = min(low[u], low[v]);
}
}
if (low[u] == dfn[u]) {
vis[u] = 0;
color[u] = ++cnt;
while (sta.top() != u) {
int v = sta.top();
sta.pop();
vis[v] = 0;
color[v] = cnt;
}
sta.pop();
}
}
void get_newedge(int u) {
for (int i = 0; i < edge[u].size(); i++) {
int v = edge[u][i];
if (color[u] == color[v])continue;
newedge[color[u]].push_back(color[v]);
in[color[v]] = 1;
out[color[u]] = 1;
}
}
int main() {
int n; cin >> n;
for (int i = 1; i <= n; i++) {
int t;
while (cin >> t) {
if (t == 0) break;
edge[i].push_back(t);
}
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) {
trajan(i);
}
}
int ans1 = 0, ans2 = 0;
for (int i = 1; i <= cnt; i++) {
get_newedge(i);
}
for (int i = 1; i <= cnt; i++) {
if (!in[i]) {
ans1++;
}
if (!out[i]) {
ans2++;
}
}
if (cnt == 1) cout << 1 <<endl<< 0 << endl;
else cout << ans1 << endl << max(ans1, ans2) << endl;
}