题解:
还是比较水的一道题
先找强连通分量缩点,然后把所有出度为0的强连通分量内c[i]c[i]的最小值相加就是答案
注意自环!
Code:Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;
int tot,head[N],n,c[N],a[N],low[N],dfn[N],mn[N],Q[N];
int flag[N],deep,color[N],top,sum,Head[N],Tot,out[N];
struct node
{
int vet,next;
}edge[N],Edge[N];
void add(int u,int v)
{
edge[++tot]=(node){v,head[u]};
head[u]=tot;
}
void Add(int u,int v)
{
Edge[++Tot]=(node){v,Head[u]};
Head[u]=Tot;
}
void tarjan(int u)
{
low[u]=dfn[u]=++deep;
Q[++top]=u;flag[u]=true;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].vet;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(flag[v])
low[u]=min(low[u],low[v]);
}
if(low[u]==dfn[u])
{
color[u]=++sum;
flag[u]=0;
while(Q[top]!=u)
{
flag[Q[top]]=false;
color[Q[top--]]=sum;
}
top--;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]!=i)add(i,a[i]);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
memset(mn,0x3f3f3f,sizeof(mn));
for(int i=1;i<=n;i++)
{
mn[color[i]]=min(mn[color[i]],c[i]);
if(color[i]!=color[a[i]]&&i!=a[i])
{
Add(color[i],color[a[i]]);
out[color[i]]++;
}
}
int ans=0;
for(int i=1;i<=sum;i++)
if(!out[i])ans+=mn[i];
printf("%d\n",ans);
return 0;
}