首先理解一下题意(我一开始其实没看懂),是先给出每个结点的左右结点,再在一行中给出每个结点的val值。我觉得有一个不好的点就是他默认了树的结点编号是按顺序1到n并且给出的左右结点正好是编号代表,没有说明清楚我感觉(个人感觉)

这个树是只有度为2的结点和度为0的结点,我们要去用两种剪刀去减去这些度为2的结点,使得最后留下的编号为1的结点的val值最大。这个两种剪刀效果一种是取左右结点val的max,另一种是取min,我们贪心思想一定是越靠近根节点的位置我们用max保证最后的值尽可能的大。这个两种剪刀的数量是确定的,用题目给定的公式再记录一下度为2结点的数量m,那么直接用m=(m+1)/2得到大剪刀的数量。

再者我解释一下为什么是用dep来决定使用大剪刀还是小剪刀,有同学可能就会想了,dep代表树的深度,那深度为m那每一层大概率不会只有一个度位2的结点吧。但是我这里就是按照dfs遍历树的深度,因为我想要的最大值一定是从某一个具体位置得来的,我直接一条直线剪到它就是了,其他树杈合并再用大剪刀浪费呢,所以遍历就按照树的深度和m比较看使用哪种剪刀最优。

感觉这种深搜和广搜的题目还是要多练......

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define l first
#define r second
#define PII pair<int,int>
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)

void solve(){
    int n;
    cin>>n;
    vector<PII>g(n+1);
    int m=0;
    int l,r;
    for(int i=1;i<=n;i++){
        cin>>g[i].l>>g[i].r;
        if(g[i].l!=0)m++;
    }
    vector<int>val(n+1);
    for(int i=1;i<=n;i++)cin>>val[i];
    m=(m+1)/2;
    auto dfs=[&](auto&&self,int dep,int u)->int{
        if(g[u].l==0){
            return val[u];
        }
        if(dep<=m){
            val[u]=max(self(self,dep+1,g[u].l),self(self,dep+1,g[u].r));
        }else{
            val[u]=min(self(self,dep+1,g[u].l),self(self,dep+1,g[u].r));
        }
        return val[u];
    };
    cout<<dfs(dfs,1,1)<<'\n';
}

signed main(){
    IOS;
    solve();
    return 0;
}