题意:
给你一棵树,每个点都有一个值a[i]。你要在一些点上放值b[i],使得对于任意一个点x,都有两个点u,v:x在u,v的路径上且min(b[u],b[v])>=a[x]。
问你最少的b之和是多少。
题解:
我把ne写成了x,找了半个小时的bug。
我们只需要将a最大的点当成根rt,然后对于任意一个x(x!=rt),只需要它的子树中有一个b>=a[x]即可。
因为在最后我们需要两个点的值>=a[rt],那么对于任意一个x(x!=rt)来说,必然至少有一个点不在它的子树中。
我们记录mx[x]表示当前子树中b的最大值,smx表示区别于mx的其它子树中的最大值。
如果当前是根的话,那么就需要有两个点来支撑他,否则只需要一个点即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+5;
vector<int>vec[N];
int a[N],mx[N],smx[N],rt;
ll ans;
void dfs(int x,int fa){
if(x-rt&&vec[x].size()==1)mx[x]=a[x],ans+=a[x];
for(int ne:vec[x]){
if(ne==fa)continue;
dfs(ne,x);
if(mx[ne]>mx[x])smx[x]=mx[x],mx[x]=mx[ne];
else if(mx[ne]>smx[x])smx[x]=mx[ne];
}
if(x-rt){
if(mx[x]<a[x])
ans+=a[x]-mx[x],mx[x]=a[x];
}
else{
if(!smx[x])ans+=a[x]+a[x]-mx[x];
else ans+=a[x]*2-mx[x]-smx[x];
}
}
int main()
{
int n,x,y;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),rt=a[rt]>=a[i]?rt:i;
for(int i=1;i<n;i++)
scanf("%d%d",&x,&y),vec[x].push_back(y),vec[y].push_back(x);
dfs(rt,0);
printf("%lld\n",ans);
return 0;
}