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;
}

被折叠的 条评论
为什么被折叠?



