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

88 lines
2.4 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;
const int N = 100010, M = 2000010; // 因为要建新图,两倍的边
int n, m; // 点数、边数
int dfn[N], low[N], ts;
int stk[N], top, in_stk[N];
int id[N], scc_cnt, sz[N];
int f[N];
int h[N], hs[N], e[M], ne[M], idx; // h: 原图;hs: 新图
void add(int h[], int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int p[N]; //原图的点权
int q[N]; //新图的点权
// tarjan求强连通分量
void tarjan(int u) {
dfn[u] = low[u] = ++ts;
stk[++top] = u;
in_stk[u] = true;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (!dfn[j]) {
tarjan(j);
low[u] = min(low[u], low[j]);
} else if (in_stk[j])
low[u] = min(low[u], dfn[j]);
}
if (dfn[u] == low[u]) {
++scc_cnt;
int x;
do {
x = stk[top--];
in_stk[x] = false;
id[x] = scc_cnt;
sz[scc_cnt]++;
// scc_cnt:强连通块的编号
q[scc_cnt] += p[x]; //叠加点权,生成连通块的总点权
} while (x != u);
}
}
int main() {
memset(h, -1, sizeof h); //原图
memset(hs, -1, sizeof hs); //新图
scanf("%d %d", &n, &m);
//读入点权
for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
for (int i = 1; i <= m; i++) {
int a, b;
scanf("%d %d", &a, &b);
add(h, a, b);
}
//利用强连通分量,缩点,生成DAG
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i);
// (2) 缩点,建图
for (int u = 1; u <= n; u++)
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
int a = id[u], b = id[j];
if (a != b) //去重边
add(hs, a, b); //加入到新图
}
// (3) 根据拓扑序遍历DAG,从scc_cnt向前遍历自然满足拓扑序
for (int u = scc_cnt; u; u--) {
// base case 递推起点
if (!f[u]) f[u] = q[u];
for (int i = hs[u]; ~i; i = ne[i]) {
int j = e[i]; // 边(i, j)
if (f[j] < f[u] + q[j]) f[j] = f[u] + q[j];
}
}
// (4) 求解答案
int res = 0;
for (int i = 1; i <= scc_cnt; i++) res = max(res, f[i]);
//输出
printf("%d\n", res);
return 0;
}