Problem - D - Codeforces
芬特队长参与了另一个寻宝活动,但只发现了一个奇怪的问题。这个问题可能与宝藏的位置有关,也可能不是。这就是为什么弗林特船长决定把解决问题的工作交给他的船员,并提供了一个高得离谱的奖励:休息一天。问题本身听起来是这样的……有两个长度为n的数组a和b。最初,ans等于0,并定义如下操作:1. 选择位置i (1 <i<n);2. 在ans的基础上加上a;3.如果b, -1,那么加a;, abi对每一个i (1 Si S n)只执行一次,你能得到的最大ans是多少?Bogdan叔叔急于得到奖励,所以他请求你帮助他找到对他们进行手术的最佳位置顺序。输入第一行包含整数n (1 < n < 2-105) -数组a和b的长度。第二行包含n个整数a1, a2,…, an(-10°< a;< 106)。第三行包含n个整数b1 b2,。,bn (1 < bi < n or b;= 1)。附加约束:它保证对于任意i (1 < i< n)序列b, bbi>bb;?不是循环的,换句话说,它总是以-1结尾。输出在第一行中,打印您可以得到的最大ans。在第二行,打印操作顺序:n个不同的整数P1,P2,Pn (1 pi S n)。p是第i步应该选择的位置。如果有多个订单,打印其中任何一个。
Examples
input
Copy
3 1 2 3 2 3 -1
output
Copy
10 1 2 3
input
Copy
2 -1 100 2 -1
output
Copy
99 2 1
input
Copy
10 -10 -1 2 2 5 -2 -3 -4 2 -6 -1 -1 2 2 -1 5 5 7 7 9
output
Copy
-9 3 5 6 1 9 4 10 7 8 2
题解:
如果bi != -1,那么如果进行第i操作,abi += ai,bi可以看作一条i -> bi的边,
又说保证是不循环的,所以构建出来的图大概是这样
由于 abi += ai,是累加操作,ai的值会多次加上,所以,从叶子节点开始操作是最优的,
所以我们进行拓扑排序,每次把入度为0的点存入,并且如果ai >= 0让他的下一个节点+ai
对于叶子节点ai < 0的时候,累计会导致多次加上一个负数,肯定是不行的,所以我们
遍历到入度为0,的点并且ai<0,把它存到栈中
拓扑排序完拿的话,就变成了,先拿-3,然后-2,-1明显这是最优情况
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define int long long
vector<int> p[200050];
int a[200050];
int n;
int du[200050];
void solve()
{
cin >> n;
for(int i = 1;i <= n;i++)
{
cin >> a[i];
}
for(int i = 1;i <= n;i++)
{
int x;
cin >> x;
if(x != -1)
{
du[x] ++;
p[i].push_back(x);
}
}
stack<int> s;
queue<int> q;
for(int i = 1;i <= n;i++)
{
if(du[i] == 0)
q.push(i);
}
vector<int> ans;
int res = 0;
while(q.size())
{
int t = q.front();
q.pop();
if(a[t] >= 0)
{
ans.push_back(t);
res += a[t];
}
else
s.push(t);
for(auto ne:p[t])
{
if(a[t] >= 0)
{
a[ne] += a[t];
}
du[ne]--;
if(du[ne] == 0)
{
q.push(ne);
}
}
}
while(s.size())
{
int t = s.top();
s.pop();
res += a[t];
ans.push_back(t);
}
cout << res <<"\n";
for(auto i:ans)
{
cout <<i<<" ";
}
}
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int t = 1;
// cin >> t;
while(t--)
{
solve();
}
}