1. 程式人生 > >經典遊戲

經典遊戲

題目描述

SUPER M是一個很經典的遊戲

現在改一下規則

有N個城堡(0到n-1)

每個城堡都有一個KOOPA,注意:有些KOOPA會可能有1個FATHER-KOOPA

公主在最後一個城堡內(N-1)

現在每次只能打一個城堡且必須在T[I]時間內打完(否則遊戲結束)

如果(N-1)號城堡打完

遊戲結束

如果一個KOOPA至少有2個SON-KOOPA被打敗

則必須馬上去擊敗這個KOOPA否則會因為憤怒而做掉公主

現在求

最長遊戲時間

題解

考慮遊戲結束是什麼情況:
n

1 n-1 的一個兒子全部打死,其他兒子除了根都儘量打了,一個兒子打到根的一刻就結束了。那麼我們通過觀察可以發現有兩個狀態需要除了:
f [ x ]
f[x]
表示這個子樹打到根節點就不打了的最大值
g [ x ] g[x] 表示這個子樹不打根節點能打到的最大值
顯然 g
[ x ] g[x]
也很好轉移,一個子樹全打死,其他都是 g [   ] g[\ ]
f [ x ] f[x] 就是一個子樹全打死一個是 f [   ] f[\ ] 其他是 g [   ] g[\ ]
注意 f [ x ] f[x] 的兩個最大是同一個的情況,要同時存 f [ x ] f[x] s u m [ x ] sum[x] 的最大值和次大值

程式碼

#include<bits/stdc++.h>
#define maxn 100005
#define MAXN 1000005
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
LL read(){
    LL res,f=1; char c;
    while(!isdigit(c=getchar())) if(c=='-') f=-1; res=(c^48);
    while(isdigit(c=getchar())) res=(res<<3)+(res<<1)+(c^48);
    return res*f;
}
struct EDGE{
    int u,v,nxt;
}e[maxn<<1];
int T,n,cnt,head[maxn],f[maxn],g[maxn],sum[maxn],w[maxn];
void add(int u,int v){
    e[++cnt]=(EDGE){u,v,head[u]};
    head[u]=cnt;
}
void DFS(int u){
    int M=0,M1=0,M2=0,m1=0,m2=0;
    sum[u]+=w[u];
    f[u]+=w[u];
    for(int i=head[u];~i;i=e[i].nxt){
        int v=e[i].v;
        DFS(v);
        sum[u]+=sum[v];
        g[u]+=g[v];
        f[u]+=g[v];
        M=max(M,sum[v]-g[v]);
        if(f[v]-g[v]>f[M1]-g[M1] || !M1){
            M2=M1;
            M1=v;
        }
        else if(f[v]-g[v]>f[M2]-g[M2] || !M2){
            M2=v;
        }
        if(sum[v]-g[v]>sum[m1]-g[m1] || !m1){
            m2=m1;
            m1=v;
        }
        else if(sum[v]-g[v]>sum[m2]-g[m2] || !m2){
            m2=v;
        }
    }
    g[u]+=M;
    if(M1!=m1){
        f[u]+=f[M1]-g[M1];
        f[u]+=sum[m1]-g[m1];
    }
    else f[u]+=max(f[M1]-g[M1]+sum[m2]-g[m2],f[M2]-g[M2]+sum[m1]-g[m1]);
}
int main(){
    while(n=read()){
        for(int i=1;i<=n;i++){
            w[i]=read();
        }
        cnt=0;
        memset(head,-1,sizeof head);
        memset(f,0,sizeof f);
        memset(g,0,sizeof g);
        memset(sum,0,sizeof sum);
        for(int i=1;i<=n;i++){
            int fa=read();
            if(~fa){add(fa+1,i);}
        }
        DFS(n);
        for(int i=1;i<=n;i++){
            if(!sum[i]) f[n]+=w[i];
        }
        printf("%d\n",f[n]);
    }
    return 0;
}