When good old friends are g|

run-away

园龄:1年7个月粉丝:1关注:0

2024-02-23 20:29阅读: 6评论: 0推荐: 0

「CF1872F」 Selling a Menagerie

题意

\(n\) 种动物,第 \(i\) 只动物有且只有一个害怕的动物 \(a_i\) 和价值 \(c_i\)。现在把所有的动物都卖出去,若 \(a_i\)\(i\) 前面卖出去,将获得 \(c_i\) 的收益;否则将多获得 \(c_i\) 的收益。构造一种使收益最大的卖出顺序。

思路

这题很明显是图,显然对于每一个动物 \(i\),先卖 \(a_i\) 比先卖 \(i\) 更优。

可以从 \(i\)\(a_i\) 连边,然后跑一遍拓扑,一边遍历一边输出当前节点。

但是,因为每个点都有一条出边,图中肯定会有一个环,拓扑后还剩下环内的节点没有考虑。

对于环内的点,先删去任何一个点都会影响后续的点,所以找到价值最小的点,从它开始删。

拓扑 \(O(n)\),遍历环 \(O(n)\),总时间复杂度 \(O(n)\)

Code(无坑)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define read(x) scanf("%lld",&x)
const ll maxn=100005;
ll t,n,a[maxn],c[maxn],du[maxn],pre[maxn],mn[maxn];
vector<ll>h;
inline ll find(ll x){return x==pre[x]?x:pre[x]=find(pre[x]);}
inline void solve(){
read(n);
for(ll i=1;i<=n;++i)pre[i]=i,du[i]=mn[i]=0;
for(ll i=1;i<=n;++i)read(a[i]),++du[a[i]];
for(ll i=1;i<=n;++i)read(c[i]);
queue<ll>p;
for(ll i=1;i<=n;++i)if(!du[i])p.push(i);
while(!p.empty()){
ll u=p.front();p.pop();
printf("%lld ",u);
if(!--du[a[u]])p.push(a[u]);
}
for(ll i=1;i<=n;++i){
if(du[i]){
pre[find(i)]=find(a[i]);
}
}
for(ll i=1;i<=n;++i){
if(du[i]&&(mn[find(i)]==0||c[mn[pre[i]]]>c[i])){
mn[pre[i]]=i;
}
}
for(ll i=1;i<=n;++i){
if(du[i]&&mn[pre[i]]==i){
for(ll j=a[i];j!=i;j=a[j]){
printf("%lld ",j);
}
printf("%lld ",i);
}
}
puts("");
}
signed main(){
read(t);
while(t--){
solve();
}
return 0;
}

本文作者:run-away

本文链接:https://www.cnblogs.com/run-away/p/18030324

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   run-away  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起