Files
cpp-courseware/2.Course/2.深入浅出程序设计竞赛(提高篇)/最短路/C++源码/07_06_p3275.cpp
T

69 lines
2.4 KiB
C++

// P3275 糖果。迭代 Kosaraju + 缩点 DAG 上的最长下界,O(n+k)。
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
int n, k; if (!(cin >> n >> k)) return 0;
vector<vector<pair<int,int>>> g(n);
vector<vector<int>> rg(n);
auto add = [&](int u, int v, int w) { g[u].push_back({v,w}); rg[v].push_back(u); };
for (int i = 0, x, a, b; i < k; ++i) {
cin >> x >> a >> b; --a; --b;
if (x == 1) { add(a,b,0); add(b,a,0); }
if (x == 2) add(a,b,1);
if (x == 3) add(b,a,0);
if (x == 4) add(b,a,1);
if (x == 5) add(a,b,0);
}
vector<bool> vis(n, false);
vector<int> order;
// 第一次 DFS:显式保存下一条边下标,退出时记录结束序。
for (int s = 0; s < n; ++s) if (!vis[s]) {
vector<pair<int,int>> st;
vis[s] = true; st.push_back({s,0});
while (!st.empty()) {
auto &[u,i] = st.back();
if (i == (int)g[u].size()) { order.push_back(u); st.pop_back(); }
else {
int v = g[u][i++].first;
if (!vis[v]) { vis[v] = true; st.push_back({v,0}); }
}
}
}
// 第二次 DFS:反图按逆结束序分组。
vector<int> comp(n, -1), size;
int count = 0;
reverse(order.begin(), order.end());
for (int s : order) if (comp[s] == -1) {
vector<int> st(1,s); comp[s] = count; int amount = 0;
while (!st.empty()) {
int u = st.back(); st.pop_back(); ++amount;
for (int v : rg[u]) if (comp[v] == -1) {
comp[v] = count; st.push_back(v);
}
}
size.push_back(amount); ++count;
}
vector<vector<pair<int,int>>> dag(count);
vector<int> indeg(count, 0), d(count, 1);
for (int u = 0; u < n; ++u) for (auto [v,w] : g[u]) {
if (comp[u] == comp[v]) {
if (w == 1) { cout << -1 << '\n'; return 0; }
} else {
dag[comp[u]].push_back({comp[v],w}); ++indeg[comp[v]];
}
}
queue<int> q;
for (int c = 0; c < count; ++c) if (indeg[c] == 0) q.push(c);
while (!q.empty()) {
int u = q.front(); q.pop();
for (auto [v,w] : dag[u]) {
d[v] = max(d[v], d[u]+w);
if (--indeg[v] == 0) q.push(v);
}
}
long long ans = 0;
for (int c = 0; c < count; ++c) ans += 1LL * size[c] * d[c];
cout << ans << '\n';
}