可以发现题目给出的是一个森林,对于每一棵树进行一次记忆化,记录走完当前节点子树后,当前节点的最大累计值。(第一问)
对于第二问,我们每次先遍历能对当前节点做出贡献的子节点(即权值为正),然后对于不能对当前节点做出贡献的子节点放在后面遍历(即无关紧要了)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,ans,tot;
int a[N],b[N],sum[N],du[N];
int cnt,head[N];
struct edge{
int next,to;}e[N];
inline void add(int u,int v)
{
cnt++;
e[cnt].next=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dfs(int u)
{
for (register int i=head[u]; i; i=e[i].next)
{
dfs(e[i].to);
if (sum[e[i].to]>0) sum[u]+=sum[e[i].to];
}
}
void dfs2(int u)
{
for (register int i=head[u]; i; i=e[i].next) if (sum[e[i].to]>=0) dfs2(e[i].to);
printf("%lld ",u);
for (register int i=head[u]; i; i=e[i].next) if (sum[e[i].to]<0) dfs2(e[i].to);
}
signed main(){
scanf("%lld",&n);
for (register int i=1; i<=n; ++i) scanf("%lld",&a[i]);
for (register int i=1; i<=n; ++i)
{
scanf("%lld",&b[i]);
if (~b[i]) add(b[i],i),du[i]++;
}
for (register int i=1; i<=n; ++i) sum[i]=a[i];
for (register int i=1; i<=n; ++i) if (!du[i]) dfs(i);
for (register int i=1; i<=n; ++i) ans+=sum[i];
printf("%lld\n",ans);
for (register int i=1; i<=n; ++i) if (!du[i]) dfs2(i);
return 0;
}