牛客挑戰賽71 B樹上博弈

Link

一道很有意思的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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章