Captain Flint and Treasure(CodeForces - 1388D ) 【拓扑排序】

芬特船长参与了另一个寻宝行动,但只发现了一个奇怪的问题。这个问题可能与宝藏的位置有关,也可能与此无关。这就是为什么弗林特船长决定把解决这个问题的任务留给他的船员,并给了他们一个高得离谱的奖励:一天假。

有两个数组a和b的长度n。初始ans = 0,定义如下操作:

1.选择位置i(1≤i≤n);

2.在ans中加上a[i];

3.如果b[i]≠- 1,则将a[b[i]]中加上a[i]。

对每个i(1≤i≤n)执行一次操作,可以得到的最大ans值是多少?

Bogdan叔叔渴望得到奖励,所以他请求你帮他找到最优的位置顺序来对它们进行操作。

Input

第一行包含整数n(1≤n≤2⋅105)——数组的长度a和b。

第二行包含n整数a1,a2,…,an(−106≤ai≤106)。

第三行包含n整数b1,b2,…,bn(1≤bi≤n或bi=−1)。

附加约束:保证对于任意i(1≤i≤n),序列b[i],b[b[i]],b[b[b[i]]],… 都不是循环的,即总是以−1结束。

Output

在第一行中,打印您可以获得的最大ans字体。

在第二行中,打印操作顺序:nn不同的整数p1,p2,…,pn(1≤pi≤n)。pi是在第i步应该选择的位置。如果有多个订单,打印其中任何一个。

Examples

Input

3
1 2 3
2 3 -1

Output

10
1 2 3

Input

2
-1 100
2 -1

Output

99
2 1

Input

10
-10 -1 2 2 5 -2 -3 -4 2 -6
-1 -1 2 2 -1 5 5 7 7 9

Output

-9
3 5 6 1 9 4 10 7 8 2

第一个样例: 1 + (1 + 2) + (3 + 3) = 10

代码

//博客,拓扑排序
#include "stdio.h"
#include "algorithm"
#include "iostream"
#include "string.h"
#include "vector"
#include "queue"
using namespace std;
int n,m;
long long sum=0;
long long a[200009],b[200009],c[200009];
//c[i]录编号为i的入度
int main()
{

	queue<int>q;//记录入度为零的编号
	vector<int>good,bad;
//good数组记录a数组中值大于0(正数的编号)的编号
//bad 数组记录a叔祖中值小于等于0(负数的编号)的编号
	cin>>n;
	for(int i=1; i<=n; i++)
		cin>>a[i];
	for(int i=1; i<=n; i++)
	{
		cin>>b[i];
		if(b[i]!=-1)
			c[b[i]]++;
//c[b[i]记录编号为b[i]的入度
	}
	for(int i=1; i<=n; i++)
	{
		if(c[i]==0)
			q.push(i);
	}
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		sum+=a[u];
		if(a[u]>0)
		{
			good.push_back(u);
			a[b[u]]+=a[u];
			c[b[u]]--;
		}
		else
		{
			bad.push_back(u);
			c[b[u]]--;
		}
		if(c[b[u]]==0)
			q.push(b[u]);
	}
	cout<<sum<<endl;
	for(int i=0; i<good.size(); i++)//正着来使一些正数可以留后代 (会加到其他数上再加到ans(sum)中) 
		cout<<good[i]<<' ';
	for(int i=bad.size()-1; i>=0; i--)//倒着来使负数断子绝孙 (不会加到其他数上再加到ans(sum)中) 
		cout<<bad[i]<<' ';
}
//为什么先输入正数的编号,再输入负数的编号
//就是把上面的55-58行写成 (交换一下顺序) 
/*
for(int i=bad.size()-1; i>=0; i--)
		cout<<bad[i]<<' ';
for(int i=0; i<good.size(); i++)
		cout<<good[i]<<' ';
*/
/*
例1	     1   -5   4 
        -1   1    2
(先正后负)ans(max)=4+1+(-5+4)=4   顺序3 1 2 
(先负后正)ans=-5+4+(1-5)=-5  顺序 2 3 1 

例2      1   -5   9 
		-1    1   2
(先正后负)ans(max)=9+1+(-5+9)=14   顺序3 1 2 
(先负后正)ans=-5+9+(1-5)=0  顺序 2 3 1 


我们发现:
先正后负可以令某些负数变大(-5-->-1)或变为正数(-5-->4) 
先负后正可以另某些正数变小或变为负数 
 
*/ 
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值