tarjan求强连通分量块,然后每个块的相互可达的点的对数就是 C n 2 C_{n}^{2} Cn2,加起来即可
#include <cstdio>
#include <stack>
#include <cstring>
#include <climits>
#include <algorithm>
const int MAXN = 1e4 + 2;
const int MAXM = 1e5 + 2;
struct Edge {
int to, next;
} edge[MAXM << 1];
static std::stack<int> s;
int tot, n, m, index, cnt, ans;
int pre[MAXN], dfn[MAXN], low[MAXN];
bool vis[MAXN];;
void addEdge(int u, int v) {
tot++;
edge[tot].to = v;
edge[tot].next = pre[u];
pre[u] = tot;
}
void tarjan(int x) {
dfn[x] = low[x] = ++cnt;
s.push(x); vis[x] = true;
for (int i = pre[x]; i; i = edge[i].next) {
if (!dfn[edge[i].to]) {
tarjan(edge[i].to);
low[x] = std::min(low[x], low[edge[i].to]);
}
else if (vis[edge[i].to]) {
low[x] = std::min(low[x], dfn[edge[i].to]);
}
}
if (low[x] == dfn[x]) {
int prev, cnt = 0;
do {
//printf("%d ", s.top());
cnt++;
vis[s.top()] = false;
prev = s.top();
s.pop();
} while (x != prev);
//printf("\n");
if (cnt >= 2) ans += cnt * (cnt - 1) / 2;
}
return;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d %d", &u, &v);
addEdge(u, v);
}
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i);
printf("%d\n", ans);
return 0;
}