LG P5008 [yLOI2018] 锦鲤抄 Solution
Description
给你一张 nnn 点 mmm 边的有向图 GGG(可能有自环),每个点有一个点权 wiw_iwi,还有一个变量 SSS,初始时 S=0S=0S=0.
你可以任意选择一个入度 >0>0>0 的点 uuu,把 uuu 和 uuu 的全部出边删掉,并让 S←S+wuS\gets S+w_uS←S+wu.
你最多能执行 kkk 次这样的操作,求 SSS 的最大可能值.
Limitations
1≤n≤5×105+41\le n\le 5\times 10^5 +41≤n≤5×105+4
1≤m≤2×106+41\le m\le 2\times 10^6+41≤m≤2×106+4
0≤wi≤103,0≤k≤n0\le w_i\le 10^3,0\le k\le n0≤wi≤103,0≤k≤n
Solution
这题有紫吗?
考虑若 GGG 是个 DAG
,那么只要按照 topo
序倒序删,所有入度 >0>0>0 的点都能删干净,选 www 前 kkk 大的即可.
否则,可以把图缩成 DAG
变成上面情况,然后只需考虑 SCC
内部如何选.
- 若一个
SCC
有入度,那么所有点都能删干净. - 若一个
SCC
没有入度,那么只有一个点无法删掉,我们显然要留下 www 最小的点. - 若一个
SCC
有自环,那么所有点也是能删干净的,需要特判.
找出所有候选点后,排序即可求出答案(当然用 nth_element
更快).
Code
1.92KB,1.19s,66.13MB (c++20 with o2)1.92\text{KB},1.19\text{s},66.13\text{MB}\;\texttt{(c++20 with o2)}1.92KB,1.19s,66.13MB(c++20 with o2)
#include <bits/stdc++.h>
using namespace std;using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;template<class T>
bool chmax(T &a, const T &b){if(a < b){ a = b; return true; }return false;
}template<class T>
bool chmin(T &a, const T &b){if(a > b){ a = b; return true; }return false;
}signed main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int n, m, k;cin >> n >> m >> k;vector<int> w(n);for (int i = 0; i < n; i++) cin >> w[i];vector<vector<int>> g(n);for (int i = 0, u, v; i < m; i++) {cin >> u >> v, u--, v--;g[u].push_back(v);}vector<int> dfn(n, -1), low(n, -1), bel(n, -1), scc;vector<bool> ins(n);stack<int> stk;int clock = 0;auto dfs = [&](auto&& self, int u) -> void {dfn[u] = low[u] = clock++;ins[u] = true, stk.push(u);for (auto v : g[u]) {if (dfn[v] == -1) self(self, v), chmin(low[u], low[v]);else if (ins[v]) chmin(low[u], dfn[v]);}if (low[u] == dfn[u]) {int id = bel[u] = scc.size();scc.push_back(u), ins[u] = false;int v = stk.top(); stk.pop();for (; v != u && !stk.empty(); v = stk.top(), stk.pop()) {bel[v] = id;if (w[v] < w[scc[id]]) scc[id] = v;ins[v] = false;}}};for (int i = 0; i < n; i++) if (dfn[i] == -1) dfs(dfs, i);vector<int> ind(scc.size());vector<bool> loop(scc.size());for (int u = 0; u < n; u++) for (auto v : g[u]) {if (bel[u] != bel[v]) ind[bel[v]]++;else if (u == v) loop[bel[u]] = true;}vector<int> candi;for (int u = 0; u < n; u++) if (ind[bel[u]] || scc[bel[u]] != u || loop[bel[u]])candi.push_back(w[u]);if (candi.size() < k) candi.resize(k);nth_element(candi.begin(), candi.begin() + k, candi.end(), greater<int>());int ans = 0;for (int i = 0; i < k; i++) ans += candi[i];cout << ans;return 0;
}