#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;
}