一道很有意思的min-max博弈
用樹上dp來解決,那麼顯然的,當前節點是誰取的會影響答案,\(dp2_{i,j}\)表示取當前階段,被Alice/Bob取走的結果,
並且這個題是取子樹上任意的節點,那麼還需要保存子樹上的信息,故使用\(dp_{i,j}\)記錄下子樹中的Alice/Bob取走的結果,然後就可以順着dp解決這個問題了。
#include<iostream>
#include<cstdio>
using namespace std;
int ans[200005];
int t;
long long c[200005];
int head[200005];
struct ed{
int to;
int ne;
}edge[200005];
int p;
void add(int f,int to){
edge[++p].to=to;
edge[p].ne=head[f];
head[f]=p;
return ;
}
int f;
long long dp[200001][2];
long long dp2[200001][2];
//k等於0表示bob來取
void dfs(int f){
if(!head[f]){
dp[f][0]=dp2[f][0]=-c[f];
dp[f][1]=dp2[f][1]=c[f];
return ;
}
dp[f][0]=dp2[f][0]=1e13;
dp[f][1]=dp2[f][1]=-1e13;
for(int i=head[f];i;i=edge[i].ne){
int to=edge[i].to;
dfs(to);
dp[f][0]=min(dp[to][0],dp[f][0]);
dp[f][1]=max(dp[f][1],dp[to][1]);
}
dp2[f][0]=dp[f][1]-c[f];
dp2[f][1]=dp[f][0]+c[f];
dp[f][0]=min(dp2[f][0],dp[f][0]);
dp[f][1]=max(dp[f][1],dp2[f][1]);
return ;
}
int n;
int main(){
scanf("%d",&t);
while(t--){
p=0;
scanf("%d",&n);
for(int i=1;i<=n;++i){
head[i]=0;
}
for(int i=2;i<=n;++i){
scanf("%lld",&c[i]);
}
for(int i=2;i<=n;++i){
scanf("%d",&f);
add(f,i);
}
dfs(1);
printf("%lld\n",dp[1][1]);
}
return 0;
}