#include <bits/stdc++.h>
using namespace std;

using ll = long long;

/*
==================== PROBLEM STATEMENT ====================

You are given a rooted tree with n nodes, rooted at node 1.
Each node i has an integer value value[i].

Define subtreeSum[u] as the sum of all values in the subtree
of node u (including u itself).

You are allowed to perform at most ONE operation:
- Choose any node u
- Change its value to ANY integer (i.e., add some delta)

Effect of this operation:
- Only node u and all its ancestors (up to the root)
  will have their subtree sums changed.

Goal:
After performing at most one operation, maximize the frequency
of any subtree sum value.

In other words:
Make as many nodes as possible have the same subtree sum.

Output:
Print the maximum possible frequency.

Constraints:
- 1 ≤ n ≤ (typical large constraints)
- Values can be large → subtree sums can be large

===========================================================
*/

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

    int n;
    cin >> n;

    // Read values of nodes (1-indexed)
    vector<ll> value(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> value[i];
    }

    /*
    Parent input may come in two formats:
    1) parent[1..n] where parent[1] = 0
    2) parent[2..n]
    So we read all remaining input and detect format
    */
    vector<int> rest;
    int x;
    while (cin >> x) {
        rest.push_back(x);
    }

    vector<int> parent(n + 1, 0);

    if ((int)rest.size() == n) {
        // Full parent array given
        for (int i = 1; i <= n; i++) {
            parent[i] = rest[i - 1];
        }
    } else {
        // parent[2..n] given
        for (int i = 2; i <= n; i++) {
            parent[i] = rest[i - 2];
        }
    }

    // Build adjacency list (tree)
    vector<vector<int>> tree(n + 1);
    for (int i = 2; i <= n; i++) {
        tree[parent[i]].push_back(i);
    }

    /*
    STEP 1: Compute subtree sums

    We do iterative DFS to get traversal order,
    then process in reverse (postorder style)
    */
    vector<int> order;
    order.reserve(n);

    stack<int> st;
    st.push(1);

    while (!st.empty()) {
        int u = st.top();
        st.pop();
        order.push_back(u);

        for (int v : tree[u]) {
            st.push(v);
        }
    }

    // subSum[u] = sum of subtree rooted at u
    vector<ll> subSum(n + 1, 0);

    // Process in reverse order (children before parent)
    for (int i = n - 1; i >= 0; i--) {
        int u = order[i];
        subSum[u] = value[u];

        for (int v : tree[u]) {
            subSum[u] += subSum[v];
        }
    }

    /*
    STEP 2: Coordinate compression

    Subtree sums can be large, so map them to [0..m-1]
    */
    vector<ll> allSums;
    allSums.reserve(n);

    for (int i = 1; i <= n; i++) {
        allSums.push_back(subSum[i]);
    }

    sort(allSums.begin(), allSums.end());
    allSums.erase(unique(allSums.begin(), allSums.end()), allSums.end());

    int m = (int)allSums.size();

    // sumId[u] = compressed id of subtree sum of node u
    vector<int> sumId(n + 1);

    // totalFreq[id] = how many nodes have this subtree sum
    vector<int> totalFreq(m, 0);

    for (int i = 1; i <= n; i++) {
        sumId[i] = lower_bound(allSums.begin(), allSums.end(), subSum[i]) - allSums.begin();
        totalFreq[sumId[i]]++;
    }

    /*
    STEP 3: DFS over all root-to-node paths

    pathFreq[id] = how many times this sum appears on current path
    totalFreq[id] - pathFreq[id] = count outside path

    We maintain:
    - onPath: multiset of frequencies on current path
    - outsidePath: multiset of frequencies outside path

    This allows O(log n) retrieval of max frequency
    */
    vector<int> pathFreq(m, 0);
    multiset<int> onPath, outsidePath;

    // Initially, path is empty → all nodes are outside
    for (int i = 0; i < m; i++) {
        onPath.insert(0);
        outsidePath.insert(totalFreq[i]);
    }

    int answer = 1;

    /*
    DFS using explicit stack:
    state = 0 → entering node
    state = 1 → exiting node (backtracking)
    */
    vector<pair<int, int>> dfs;
    dfs.push_back({1, 0});

    while (!dfs.empty()) {
        auto [u, state] = dfs.back();
        dfs.pop_back();

        int id = sumId[u];

        if (state == 0) {
            // -------- ENTER NODE --------

            // Remove old values before updating
            onPath.erase(onPath.find(pathFreq[id]));
            outsidePath.erase(outsidePath.find(totalFreq[id] - pathFreq[id]));

            // Include this node in path
            pathFreq[id]++;

            // Insert updated values
            onPath.insert(pathFreq[id]);
            outsidePath.insert(totalFreq[id] - pathFreq[id]);

            /*
            Best result if we modify this path:
            = best freq on path + best freq outside path
            */
            int bestOnPath = *onPath.rbegin();
            int bestOutside = *outsidePath.rbegin();

            answer = max(answer, bestOnPath + bestOutside);

            // Schedule exit (backtracking)
            dfs.push_back({u, 1});

            // Visit children
            for (int i = (int)tree[u].size() - 1; i >= 0; i--) {
                dfs.push_back({tree[u][i], 0});
            }

        } else {
            // -------- EXIT NODE --------

            // Remove current values
            onPath.erase(onPath.find(pathFreq[id]));
            outsidePath.erase(outsidePath.find(totalFreq[id] - pathFreq[id]));

            // Remove node from path
            pathFreq[id]--;

            // Insert updated values
            onPath.insert(pathFreq[id]);
            outsidePath.insert(totalFreq[id] - pathFreq[id]);
        }
    }

    cout << answer << '\n';
    return 0;
}