经典游戏

xiaoxiao2025-06-12  14

题目描述

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 n1的一个儿子全部打死,其他儿子除了根都尽量打了,一个儿子打到根的一刻就结束了。那么我们通过观察可以发现有两个状态需要除了: f [ x ] f[x] f[x]表示这个子树打到根节点就不打了的最大值 g [ x ] g[x] g[x]表示这个子树不打根节点能打到的最大值 显然 g [ x ] g[x] g[x]也很好转移,一个子树全打死,其他都是 g [   ] g[\ ] g[ ] f [ x ] f[x] f[x]就是一个子树全打死一个是 f [   ] f[\ ] f[ ]其他是 g [   ] g[\ ] g[ ] 注意 f [ x ] f[x] f[x]的两个最大是同一个的情况,要同时存 f [ x ] f[x] f[x] s u m [ x ] sum[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; }
转载请注明原文地址: https://www.6miu.com/read-5031750.html

最新回复(0)