好妙,可以用拓扑排序去做。
首先我们要明白,我们先统计正数的,再去统计负数,这么做是最优的。正数的话,加上去另个一个数,一定会使得答案更优,而且题目说保证不会成环,所以拓扑排序是可以的。然后我们对负数的处理就是,按照拓扑序逆序处理。因为负数无论加到哪里,都会使得答案变差,按照拓扑序逆序,可以防止负数加到另一个数,具体细节看代码吧。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<map>
#include<vector>
#include<list>
#include<queue>
#define int long long
using namespace std;
int n,a[200005],b[200005],ru[200005],ans=0,v1[200005],v2[200005],cnt1,cnt2;
list<int>lis[200005];
queue<int>q;
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&b[i]);
if(b[i]==-1)continue;
lis[i].push_back(b[i]);
ru[b[i]]++;
}
for(int i=1;i<=n;i++)
{
if(!ru[i])q.push(i);
}
while(!q.empty())
{
int x=q.front();q.pop();
ans+=a[x];
for(list<int>::iterator it=lis[x].begin();it!=lis[x].end();it++)
{
ru[*it]--;
if(!ru[*it])q.push(*it);
if(a[x]>0)a[*it]+=a[x];
}
if(a[x]>=0)v1[++cnt1]=x;
else v2[++cnt2]=x;
}
cout<<ans<<endl;
for(int i=1;i<=cnt1;i++)
{
printf("%lld ",v1[i]);
}
for(int i=cnt2;i>=1;i--)
{
printf("%lld ",v2[i]);
}
}