Files
python/TangDou/AcWing/SCC/368_SCC_QC.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

99 lines
2.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100010, M = 600010;
int n, m;
int h[N], hs[N], e[M], ne[M], w[M], idx;
void add(int h[], int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int dist[N];
// tarjan求scc
int dfn[N], low[N], ts, stk[N], top, in_stk[N];
int id[N], scc_cnt, sz[N];
void tarjan(int u) {
dfn[u] = low[u] = ++ts;
stk[++top] = u;
in_stk[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (in_stk[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
++scc_cnt;
int x;
do {
x = stk[top--];
in_stk[x] = 0;
id[x] = scc_cnt;
sz[scc_cnt]++;
} while (x != u);
}
}
int main() {
scanf("%d %d", &n, &m);
memset(h, -1, sizeof h);
memset(hs, -1, sizeof hs);
// 0号超级源点
// ∵ 恒星的亮度最暗是 1
// ∴ 0 ~ i 有一条边权为1的边
for (int i = 1; i <= n; i++) add(h, 0, i, 1);
// 求最小->求所有下界的最大->最长路 √
while (m--) {
int t, a, b;
scanf("%d %d %d", &t, &a, &b);
if (t == 1) // a=b
add(h, b, a, 0), add(h, a, b, 0);
else if (t == 2) // a < b --> b>=a+1
add(h, a, b, 1);
else if (t == 3) // a>=b+0
add(h, b, a, 0);
else if (t == 4) // a>=b+1
add(h, b, a, 1);
else
add(h, a, b, 0); // b>=a+0
}
// 超级源点+强连通分量+缩点
tarjan(0);
unordered_set<LL> S; // 对连着两个不同强连通分量的边进行判重
for (int u = 0; u <= n; u++) { // 添加上超级源点,就是n+1个点
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
int a = id[u], b = id[v];
LL hash = a * 1000000ll + b; // 新两点a,b之间的Hash值,防止出现重边
if (a == b) {
if (w[i] > 0) { // 在同一个强连通分量中,存在边权大于0的边
puts("-1"); // 必然有正环,最长路存在正环,原不等式组无解
exit(0);
}
} else if (!S.count(hash))
add(hs, a, b, w[i]); // 建新图
}
}
for (int u = scc_cnt; u; u--) // 倒序输出拓扑序
for (int i = hs[u]; ~i; i = ne[i]) {
int v = e[i];
dist[v] = max(dist[v], dist[u] + w[i]);
}
// 因为不存在正环,而且题目保证都是路径>=0,所以强连通分量中必然路径长度都是0
// 即是一样一样的东西
LL res = 0;
for (int i = 1; i <= scc_cnt; i++) res += (LL)dist[i] * sz[i];
printf("%lld\n", res);
return 0;
}