abc256_e Takahashi's Anguish 题解
Takahashi's Anguish
题意
有 \(n\) 个人,每个人都有一个看不惯的人,第 \(i\) 个人看不惯 \(x_i\),如果 \(x_i\) 站在 \(i\) 的前面,则会产生 \(c_i\) 的不愉悦值。
求一个排列顺序,使得产生的不愉悦值最小,求最小值。
思路
做题之前先推样例。——鲁迅
其实带点模板的意味,每次建立一条从 \(x_i\) 到 \(i\) 的边,边权为 \(c_i\),那么样例就是这样:
能够发现,样例的答案来源于那条用红笔圈出来的边,思路也很明显了,对于不构成环的一些边来说,必然存在一种排列方法使得这些人不会不愉悦;而对于一个环呢?它必然会使得某个人不愉悦,只要把那个边权最小的加到答案即可。
Code
点击查看代码
#include <iostream>
#include <vector>
using namespace std;
using pr = pair<int, int>;
using ll = long long;
const int N = 2e5 + 10;
int n, a[N], c, f[N], stk[N], top; // stack 维护环上边的权值
vector<pr> v[N];
ll ans;
void dfs (int x) {
if (f[x]) {
if (f[x] == 1) { // 判断构成环
int sum = 1e9 + 10;
for (int i = 0; i < top; i++) {
sum = min(sum, stk[i]); // 选择边权最小值,加入答案
}
ans += sum;
}
return ;
}
f[x] = 1; // 标记在环上
for (pr i : v[x]) {
stk[top++] = i.second; // 将边权压入栈
dfs(i.first);
top--; // 弹出栈顶
}
f[x] = 2; // 标记不在环上但走过这个点
}
int main () {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> c;
v[a[i]].push_back({i, c}); // 建图
}
for (int i = 1; i <= n; i++) {
dfs(i); // 对每个点都要经行遍历
}
cout << ans;
return 0;
}