洛谷U643948 你爱我,我爱你 题解 强连通分量模板题

题目链接:https://www.luogu.com.cn/problem/U643948

题目大意:

给你一个有向图,求图中能够相互可达的节点对数。

解题思路:

同一个强连通分量内的任意两点之间相互可达。

所以,如果一个强连通分量的大小为 \(sz\),则其中相互可达的节点对数为 \(C_{sz}^2 = \frac{sz(sz-1)}{2}\)

答案为 \(\sum \frac{sz(sz-1)}{2}\)

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;

int n, m, dfn[maxn], low[maxn], bl[maxn], ts, scc, sz[maxn];
bool ins[maxn];
stack<int> stk;
vector<int> g[maxn];
long long ans;

void tarjan(int u) {
    dfn[u] = low[u] = ++ts;
    stk.push(u);
    ins[u] = true;
    for (auto v : g[u]) {
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (ins[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (low[u] == dfn[u]) {
        scc++;
        int v;
        do {
            v = stk.top();
            stk.pop();
            ins[v] = false;
            bl[v] = scc;
            sz[scc]++;
        } while (u != v);
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0, u, v; i < m; i++) {
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
    }
    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);
    for (int i = 1; i <= scc; i++) {
        ans += 1ll * sz[i] * (sz[i] - 1) / 2;
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2025-12-23 10:20  quanjun  阅读(2)  评论(0)    收藏  举报