解题思路
- 二叉树遍历通常利用递归的思想,粗略地写了一版(链接前向星存图),令ans表示二叉树中的最大路径和,ansi表示以nodei为节点的最大路径和,那么ans必定是ansi中的某一个。
- 在遍历的过程中,对于任意一个节点i的left分支和right分支,记录其较大者mx和较小者mn(注意不一定存在),ans=max(ans,wi,mx,wi+mx,wi+mn+mx)。
- 利用dpi记录经过nodei的到某一节点的较大分支,则有dpi=max(dp[i],wi+mx),用于i的father计算经过其的最大路径和。
- 后续再给出优化的代码。
//粗糙的版本。
#include<bits/stdc++.h>
using namespace std;
struct edge{
    int to, next, w;
}es[100005];
int head[100005];
int ans = INT_MIN, cnt = 0;
void add_edge(int from, int to){
    es[++cnt].next = head[from];
    es[cnt].to = to;
    head[from] = cnt;
}
int dp[100005];
int weight[100005];
int solve(int i){
    if(dp[i] == INT_MIN) return dp[i];
    if(head[i] == 0) {
        dp[i] = weight[i];
        ans = max(ans, weight[i]);
        }
    else{
        int tmp;
        int mn = INT_MAX;
        int mx = INT_MIN;
        int cc = 0;
        for(int j = head[i]; j != 0; j=es[j].next){//利用cc记录分支的个数,如果cc为1,则路径中没有mn
            cc++;
            tmp = solve(es[j].to);
            mn = min(mn,tmp);
            mx = max(mx,tmp);
        }
        dp[i] = max(dp[i],weight[i] + mx);//记录经过i节点的最大分支。
        ans = max(ans, max(weight[i],max(mx+weight[i],max(mx+(cc<=1?0:mn)+weight[i],mx))));//寻求最大路径和
    }
    return dp[i];
}
int main(){
    int n;
    cin>>n;
    for(int i = 1; i <= n; ++i){
        cin>>weight[i];
    }
    int root;
    memset(dp,INT_MIN,sizeof(dp));
    for(int i = 1; i <= n; ++i){
        int tmp;
        cin>>tmp;
        if (tmp == 0) root = i;
        else{
            add_edge(tmp,i);
        }
    }
    solve(root);
    cout<<ans<<endl;
    return 0;
}