經典遊戲
阿新 • • 發佈:2018-11-01
題目描述
SUPER M是一個很經典的遊戲
現在改一下規則
有N個城堡(0到n-1)
每個城堡都有一個KOOPA,注意:有些KOOPA會可能有1個FATHER-KOOPA
公主在最後一個城堡內(N-1)
現在每次只能打一個城堡且必須在T[I]時間內打完(否則遊戲結束)
如果(N-1)號城堡打完
遊戲結束
如果一個KOOPA至少有2個SON-KOOPA被打敗
則必須馬上去擊敗這個KOOPA否則會因為憤怒而做掉公主
現在求
最長遊戲時間
題解
考慮遊戲結束是什麼情況:
的一個兒子全部打死,其他兒子除了根都儘量打了,一個兒子打到根的一刻就結束了。那麼我們通過觀察可以發現有兩個狀態需要除了:
表示這個子樹打到根節點就不打了的最大值
表示這個子樹不打根節點能打到的最大值
顯然
也很好轉移,一個子樹全打死,其他都是
就是一個子樹全打死一個是
其他是
注意
的兩個最大是同一個的情況,要同時存
和
的最大值和次大值
程式碼
#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;
}