1027D. Mouse Hunt(1700)
分析:每个点有且仅有一条出边,也就是基环内向树。
所有的老鼠最终都会跑到环里,我们只要把捕鼠夹放在这个环里的最小花费的地方,就可以捕捉所有老鼠。
我们使用有向图的强连通分量,出度为0的强连通分量就是基环。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 200005;
const int M = 200005;
int dfn[N], low[N], timestamp;
int stk[N], in_stk[N], top;
int scc_cnt;
int id[N];
int h[N], e[M], ne[M], idx;
int c[N];
vector<int> scc[N];
vector<int> v[N];
int d[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++timestamp;
stk[++top] = u, in_stk[u] = true;
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (!dfn[j])
{
tarjan(j);
low[u] = min(low[u], low[j]);
}
else if (in_stk[j])
low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u])
{
int y;
++scc_cnt;
do {
y = stk[top--];
in_stk[y] = false;
id[y] = scc_cnt;
scc[scc_cnt].push_back(y);
} while (y != u);
}
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &c[i]);
memset(h, -1, sizeof h);
int a;
for (int i = 1; i <= n; ++i)
{
scanf("%d", &a);
add(i, a);
}
for (int i = 1; i <= n; ++i)
if (!dfn[i])
tarjan(i);
for (int i = 1; i <= n; ++i)
{
v[id[i]].push_back(c[i]);
for (int j = h[i]; j != -1; j = ne[j])
{
int k = e[j];
if (id[i] != id[k]) ++d[id[i]];
}
}
long long res = 0;
for (int i = 1; i <= scc_cnt; ++i)
{
if (d[i] == 0)
{
sort(v[i].begin(), v[i].end());
res += v[i][0];
}
}
printf("%lld\n", res);
return 0;
}