题目链接
Codeforces Round 660 (Div. 2) D. Captain Flint and Treasure
思路
对于第 i i i个数,如果 b i ≠ − 1 b_{i} \ne -1 bi=−1,则第 i i i个数的值 a i a_{i} ai就可以叠加到第 b i b_{i} bi个数上。
因此,如果当前 a i a_{i} ai的值是大于等于 0 0 0的,则下一个选择第 b i b_{i} bi个数对答案产生的贡献就是最优的。如果 a i a_{i} ai的值是小于 0 0 0的,可以将其放到排列的后面。
每一个 i i i都只对应一个 b i b_{i} bi,而题目规定 b i , b b i , b b b i , . . . . . . b_{i},b_{b_{i}},b_{b_{b_{i}}},...... bi,bbi,bbbi,......都不是循环的。因此我们可以从 i i i向 b i b_{i} bi连一条有向边,最后形成的图一定是一个拓扑图。
因此我们可以使用拓扑排序直接计算最终的排列,对于 a i < 0 a_{i} < 0 ai<0的点,我们可以将其放入一个栈中,在最后统计到排列里。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> pii;
const int N = 2e5 + 5, M = 1e4 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n, ans;
int a[N], b[N], du[N];
bool st[N];
vector<int>dfn, tmp;
vector<int>mp[N];
void topsort()
{
queue<int>q;
for (int i = 1; i <= n; i++)
{
if (!du[i])
{
q.push(i);
}
}
while (q.size())
{
int u = q.front();
ans += a[u];
q.pop();
if (a[u] >= 0) dfn.push_back(u);
else tmp.push_back(u);
for (int j : mp[u])
{
if (a[u] >= 0) a[j] += a[u];
du[j]--;
if (du[j] == 0)
{
q.push(j);
}
}
}
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
for (int i = 1; i <= n; i++)
{
cin >> b[i];
}
for (int i = 1; i <= n; i++)
{
if (b[i] != -1)
{
mp[i].push_back(b[i]);
du[b[i]]++;
}
}
topsort();
reverse(tmp.begin(), tmp.end());
if (tmp.size())
{
for (int val : tmp)
dfn.push_back(val);
}
cout << ans << endl;
for (int val : dfn)
{
cout << val << " ";
}
cout << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}