连通分量
通过 Tanjar 对有向图缩点
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7, inf = 1e9 + 7;
struct edge {
int u, v;
} e[N];
int dfn[N], lt[N], st[N], low[N], a[N], siz[N], f[N], indu[N];
int n, m, tim, ans = -inf;
queue <int> q;
vector <int> g[N], G[N];
inline void tanjar(int u)
{
low[u] = dfn[u] = ++ tim;
st[++ st[0]] = u;
for (int v : g[u])
{
if (!dfn[v])
{
tanjar(v);
low[u] = min(low[v], low[u]);
}
else if (!lt[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u])
{
lt[u] = ++ lt[0];
siz[lt[0]] += a[u];
while (st[st[0]] != u)
{
lt[st[st[0]]] = lt[0];
siz[lt[0]] += a[st[st[0]]];
st[0] --;
}
st[0] --;
}
}
int main()
{
scanf("%lld%lld",&n,&m);
for (int i = 1; i <= n; ++ i)
{
scanf("%lld",&a[i]);
}
for (int i = 1; i <= m; ++ i)
{
scanf("%lld%lld",&e[i].u,&e[i].v);
g[e[i].u].push_back(e[i].v);
}
for (int i = 1; i <= n; ++ i)
{
if (!dfn[i]) tanjar(i);
}
for (int i = 1; i <= m; ++ i)
{
int u = lt[e[i].u];
int v = lt[e[i].v];
if (u == v) continue;
G[u].push_back(v);
indu[v] ++;
}
for (int i = 1; i <= lt[0]; ++ i)
{
// f[i] = -inf;
if (indu[i] == 0)
{
q.push(i);
f[i] = siz[i];
}
}
while (!q.empty())
{
int u = q.front();
q.pop();
for (int v : G[u])
{
f[v] = max(f[v], f[u]+siz[v]);
indu[v] --;
if(indu[v] == 0) q.push(v);
}
}
for (int i = 1; i <= lt[0]; ++ i) ans = max(ans, f[i]);
printf("%lld",ans);
return 0;
}
通过 Tanjar 所求出的割点
#include <bits/stdc++.h>
using namespace std;
int low[21000], dfn[21000], n, m, tim, root, cnt;
vector <int> g[21000];
bool vis[21000];
inline void tanjar(int u, int fa)
{
dfn[u] = low[u] = ++ tim;
int col = 0;
for (int v : g[u])
{
if (!dfn[v])
{
col ++;
tanjar(v, u);
low[u] = min(low[u], low[v]);
// 两种割点的判断方式
if (u == root && col > 1)
{
if (!vis[u]) vis[u] = 1, cnt ++;
}
if (u != root && dfn[u] <= low[v])
{
if (!vis[u]) vis[u] = 1, cnt ++;
}
}
else if (fa != v)
{
low[u] = min(low[u], dfn[v]);
}
}
}
int main()
{
cin >> n >> m;
for (int i = 1, u, v; i <= m; ++ i)
{
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 1; i <= n; ++ i)
{
if (!dfn[i])
{
root = i;
tanjar(i, 0);
}
}
cout << cnt << '\n'; // 割点数量
for (int i = 1; i <= n; ++ i)
{
if (vis[i]) cout << i << ' '; // 割点
}
return 0;
}