题意:给你一棵以1为根的树,问截取他的两棵子树,这两棵子树上的节点的值全加起来的最大值为多少,并且这两棵子树不能有公共的节点。如果不存在这样的两棵子树,输出"Impossible".
首先是不存在的情况,当给出的一棵树为一条链的时候就是不存在的。
然后就是如何求值,我们把选子树看成选择树上的一个节点u,那么我们就需要以u为根的树上的点值的总和,我们用一个数组cot存,其次,因为要求最大值,那么我们还需要一个man数组来表示以u为根的树的所有子树的值的最大值
得到cot数组和man数组后,我们可以对每个有两个及两个以上子节点的节点进行ans = max(ans,第一大+第二大);
具体实现见以下代码。(写完都不知道这是树形dp。。。)
#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
long long n,man[maxn],cot[maxn],a[maxn],ans = -INF;
int x,y;
bool vis[maxn];
vector<int>vec[maxn];
pair<ll,ll> dfs(int u){
pair<ll,ll>tmp;
bool flag = 0;
vector<ll>gao;
for(int i=0;i<vec[u].size();++i){
if(!vis[vec[u][i]]){
vis[vec[u][i]]=1;
flag = 1;
tmp = dfs(vec[u][i]);
gao.push_back(tmp.second);
man[u]=max(man[u],tmp.second);
cot[u]+=tmp.first;
}
}
if(gao.size()>=2){
sort(gao.begin(),gao.end());
ans = max(ans,gao[gao.size()-1]+gao[gao.size()-2]);
}
man[u]=max(man[u],cot[u]);
return make_pair(cot[u],man[u]);
}
int main(){
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%I64d",&a[i]),cot[i]=a[i],man[i]=-INF;
for(int i=0;i<n-1;++i)scanf("%d%d",&x,&y),vec[x].push_back(y),vec[y].push_back(x);
vis[1]=1;
dfs(1);
//for(int i=1;i<=n;++i)printf("%d %d\n",cot[i],man[i]);
if(ans == -INF)printf("Impossible\n");
else printf("%I64d\n",ans);
}