题目链接:HDU - 6409
假设一次都不能选一对兄弟。
那么我们肯定是贪心,对每个节点选最大的权值的儿子,现在可以选一对兄弟,那么我们选一个最优的次大值加上即可。
最小值同理。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f3f3f3f3f;
int n,a[N],mx1[N],mx2[N],mi1[N],mi2[N],res1,res2,mmx,mmi;
vector<int> g[N];
void dfs(int x){
for(int to:g[x]){
dfs(to);
if(a[to]>mx1[x]) mx2[x]=mx1[x],mx1[x]=a[to];
else if(a[to]>mx2[x]) mx2[x]=a[to];
if(a[to]<mi1[x]) mi2[x]=mi1[x],mi1[x]=a[to];
else if(a[to]<mi2[x]) mi2[x]=a[to];
}
if(mx1[x]>0) res1+=mx1[x];
if(mi1[x]<0) res2+=mi1[x];
mmx=max(mmx,mx2[x]),mmi=min(mmi,mi2[x]);
}
inline void solve(){
cin>>n; mmx=-inf,mmi=inf; res1=res2=0;
for(int i=1;i<=n;i++) g[i].clear(),mx1[i]=mx2[i]=-inf,mi1[i]=mi2[i]=inf;
for(int i=2,x;i<=n;i++) scanf("%lld",&x),g[x].push_back(i);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
if(a[1]>0) res1=a[1];
if(a[1]<0) res2=a[1];
dfs(1);
printf("%lld %lld\n",res1+max(0LL,mmx),res2+min(0LL,mmi));
}
signed main(){
int T; cin>>T; while(T--) solve();
return 0;
}