一、题目
二、解法
最后形成的强联通分量肯定是一个环,每个点的出度一直为 (1),那么我们只要让入度也都为 (1) 即可。
每个点保留权值最大的入边,其他入边贪心断开即可。
但是这样还有问题,操作过后可能会形成若干个环,我们要把这些小环接成一个大环。那么一个环上至少满足一个点他断开了环边,所以我们处理出非环边的最大权值,然后贪心地看替换环上哪个点最好即可。
注意特判整张图是一个大环的情况,时间复杂度 (O(n))
三、总结
这个贪心实在是太简洁了,我觉得它的本质是拆分,把最后是一个环这种大限制拆成了每个点入度为 (1) 的小限制,只考虑单点是非常容易的(我觉得单点限制优于整体限制),再考虑例外来修正我们的限制转化即可。
( t UPD 2021/11/18):我觉得这道题就是构造答案下界,你会发现每一步都是必要的。
#include <cstdio>
#include <iostream>
using namespace std;
const int M = 100005;
#define int long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,ans,a[M],c[M],mx[M],cl[M],vis[M];
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
a[i]=read();c[i]=read();
ans+=c[i];
}
for(int i=1;i<=n;i++)
if(vis[i]==0)
{
int x=0,y=0,cnt=0;
for(x=i;vis[x]==0;x=a[x]) vis[x]=i;
if(vis[x]==i)//have this kind of color
{
for(y=x;vis[y]!=-1;y=a[y])
vis[y]=-1,cnt++;//cycle tag
}
if(cnt==n) {puts("0");return 0;}
}
for(int i=1;i<=n;i++)
{
mx[a[i]]=max(mx[a[i]],c[i]);
if(vis[i]!=-1) cl[a[i]]=max(cl[a[i]],c[i]);
}
for(int i=1;i<=n;i++)
ans-=mx[i];
for(int i=1;i<=n;i++)
if(vis[i]==-1)
{
int mi=1e9;
for(int x=i;vis[x]==-1;x=a[x])
mi=min(mi,mx[x]-cl[x]),vis[x]=0;
ans+=mi;
}
printf("%lld
",ans);
}