https://codeforces.com/contest/1388/problem/D
拓扑排序,如果a[u]>0,说明先拿a[u]再拿a[v]会大一些,如果a[u]<0,那么就先把v所在的集合拿完,再拿u所在的集合,才能让a[u]不使得a[v]变小
所以先拓扑排序顺便用并查集合并,然后把每一个集合里的元素输出顺序先拓扑排序存起来,然后把拓扑排序过程中的反向边连起来,得到集合的输出顺序。
其实有更短一些的写法就是直接建反向边,然后dfs从底向上反向转移求得答案,这样输出方案十分方便
upd
看了jiangly的代码,我傻逼了,直接正序拓扑排序的时候正序就建正边,不能就建反边,不一定要一整个集合顺序都满足,只要u->v当a[u]<0时变成v->u的边就行了,也就是v在u之前任意时刻出现都行。后面是辣鸡代码
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,cas,k,cnt,tot;
ll ans;
int b[maxl],du[maxl];
ll a[maxl];
char s[maxl];
bool in[maxl];
vector<int> e[maxl];
struct lne
{
int u,v;
}fed[maxl];
queue<int> q;
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
if(b[i]!=-1)
du[b[i]]++;
}
}
inline void mainwork()
{
for(int i=1;i<=n;i++)
if(du[i]==0)
q.push(i);
int u,v,x,y;ans=0;
while(!q.empty())
{
u=q.front();q.pop();
ans+=a[u];v=b[u];
if(v==-1) continue;
if(a[u]>=0)
{
e[u].push_back(v);
a[v]+=a[u];
}
else
e[v].push_back(u);
if(--du[v]==0)
q.push(v);
}
}
inline void print()
{
printf("%lld\n",ans);
for(int i=1;i<=n;i++)
du[i]=0;
for(int i=1;i<=n;i++)
for(int v:e[i])
du[v]++;
for(int i=1;i<=n;i++)
if(du[i]==0)
q.push(i);
int u,v;
while(!q.empty())
{
u=q.front();q.pop();
printf("%d ",u);
for(int v:e[u])
if(--du[v]==0)
q.push(v);
}
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,cas,k,cnt,tot;
ll ans;
int b[maxl],du[maxl],c[maxl],fdu[maxl],f[maxl];
ll a[maxl];
char s[maxl];
bool in[maxl];
vector<int> e[maxl],g[maxl],fe[maxl],out[maxl];
vector<int> nod;
struct lne
{
int u,v;
}fed[maxl];
queue<int> q;
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
f[i]=i;
if(b[i]!=-1)
du[b[i]]++;
}
}
inline int find(int x)
{
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
inline void mainwork()
{
for(int i=1;i<=n;i++)
if(du[i]==0)
q.push(i);
int u,v,x,y;ans=0;
while(!q.empty())
{
u=q.front();q.pop();
ans+=a[u];
v=b[u];
if(v==-1) continue;
if(a[u]>=0)
{
a[v]+=a[u];
x=find(u);y=find(v);
f[x]=y;
}
else
fed[++tot]=lne{v,u};
du[v]--;
if(!du[v])
q.push(v);
}
for(int i=1;i<=n;i++)
g[find(i)].push_back(i);
for(int i=1;i<=n;i++)
if(find(i)==i)
{
nod.push_back(i);
for(int d:g[i])
du[i]=0;
for(int d:g[i])
if(b[d]!=-1 && find(b[d])==i)
du[b[d]]++;
for(int d:g[i])
if(du[d]==0)
q.push(d);
while(!q.empty())
{
u=q.front();q.pop();
out[i].push_back(u);
v=b[u];
if(b[u]==-1 || find(v)!=i)
continue;
du[v]--;
if(!du[v])
q.push(v);
}
}
}
inline void print()
{
printf("%lld\n",ans);
for(int d:nod)
du[d]=0;
for(int i=1;i<=tot;i++)
{
fe[find(fed[i].u)].push_back(find(fed[i].v));
du[find(fed[i].v)]++;
}
for(int d:nod)
if(du[d]==0)
q.push(d);
int u,v;
while(!q.empty())
{
u=q.front();q.pop();
for(int x:out[u])
printf("%d ",x);
for(int v:fe[u])
{
--du[v];
if(du[v]==0)
q.push(v);
}
}
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}