CF1872F 题解

洛谷传送门 & CF 传送门

思路

我们可以先找到入度为 00(即没动物害怕它)的动物,先卖掉这些动物就行了。然后进行拓扑排序,把它们害怕的动物的入度减一,直到大家形成了环后不能继续拓扑排序了就行。剩下每个连通块肯定都是一个环,因为每个点的出度都是 11。我们可以利用并查集判连通块。对于每个环,我们只要让代价最小(cic_i 最小)的动物最后删掉就行了。剩下的事情就交给 SPJ 了,我们的事情已经结束了。

代码

# include <bits/stdc++.h>
using namespace std;
int t, n, a[100005], b[100005], du[100005], f[100005], x, mini[100005];
queue <int> q;
int find (int x) { //并查集找爹函数,不用讲了吧
	return x == f[x] ? x : f[x] = find (f[x]); //爸爸的爸爸叫什么?爸爸的爸爸叫爸爸
}
int main () {
	cin >> t;
	while (t --) {
		cin >> n;
		for (int i = 1; i <= n; ++ i)
			mini[i] = du[i] = 0, f[i] = i; //多组数据要初始化
		for (int i = 1; i <= n; ++ i)
			cin >> a[i], ++ du[a[i]]; //du[i] 表示有几只动物怕 i
		for (int i = 1; i <= n; ++ i)
			cin >> b[i];
		for (int i = 1; i <= n; ++ i)
			if (! du[i]) //没人怕 i
				q.push (i); //先插进去
		while (! q.empty ()) { //拓扑排序
			x = q.front ();
			q.pop ();
			cout << x << ' ';
			if (! -- du[a[x]])
				q.push (a[x]);
		}
		for (int i = 1; i <= n; ++ i)
			if (du[i]) //还有动物怕它,说明它在一个环内
				f[find (i)] = find (a[i]); //并查集找连通块(环)
		for (int i = 1; i <= n; ++ i)
			if (du[i] && (! mini[find (i)] || b[mini[f[i]]] > b[i])) //找到每个连通块内代价最小的动物
				mini[f[i]] = i;
		for (int i = 1; i <= n; ++ i)
			if (du[i] && i == mini[f[i]]) { //是这个连通块内最小的动物
				for (int j = a[i]; j != i; j = a[j]) //开始遍历环
					cout << j << ' ';
				cout << i << ' '; //别忘了自己
			}
		cout << '\n'; //别忘了换行
	}
	return 0;
}
posted @ 2023-09-20 09:04  Vitamin_B  阅读(8)  评论(0)    收藏  举报  来源