题目链接
思路:有点和求树上的最大子段和差不多,但略有不同,因为cut了一条边以后它的所有子树和都要算进去,我们设dp【i】为i的子树中子树的sum和最大的,之后遍历i的子节点,每次选最大的两个来cut,记录答案取max。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+1;
const ll inf=1e18;
ll ans=-inf,dp[maxn],a[maxn],sum[maxn],max1,max2;
vector<int>g[maxn];
void dfs(int u,int fa)
{
sum[u]=a[u];
ll max1=-inf,max2=-inf;
for(int to:g[u])
{
if(to==fa) continue;
dfs(to,u);
sum[u]+=sum[to];
}
dp[u]=sum[u];
for(int to:g[u])
{
if(to==fa) continue;
dp[u]=max(dp[u],dp[to]);
}
for(int to:g[u])
{
if(to==fa) continue;
if(dp[to]>max1) max2=max1,max1=dp[to];
else if(dp[to]>max2) max2=dp[to];
}
if(max2!=-inf) ans=max(ans,max1+max2);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
for(int i=1,u,v;i<n;++i)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
if(ans>-inf) printf("%lld\n",ans);
else printf("Impossible\n");
}