#include using namespace std; typedef long long LL; const int N = 3010, M = N << 4; const LL mod = 19491001; // 链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } int n, m; // 最简并查集 int p[N]; int find(int x) { if (x == p[x]) return x; return p[x] = find(p[x]); } LL f[N]; int dfn[N], low[N], ts; int stk[N], top; int bcnt; /* // 边双模板 vector bcc[N]; int dcc[N]; void tarjan(int u, int from) { dfn[u] = low[u] = ++ts; stk[++top] = u; for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (!dfn[v]) { tarjan(v, i); low[u] = min(low[u], low[v]); } else if (i != (from ^ 1)) low[u] = min(low[u], dfn[v]); } if (dfn[u] == low[u]) { ++bcnt; int x; do { x = stk[top--]; bcc[bcnt].push_back(x); // 记录边双中有哪些点 dcc[x] = bcnt; // 反向记录x这个点在bcnt这个边双里面 } while (x != u); } } */ int dcc[N]; // 记录每一个节点在哪个边双中 bool vis[M << 1]; void tarjan(int u, int fa) { low[u] = dfn[u] = ++ts; stk[++top] = u; for (int i = h[u]; ~i; i = ne[i]) { if (vis[i]) continue; if ((i == fa) || ((i ^ 1) == fa)) continue; int v = e[i]; if (!dfn[v]) { vis[i] = vis[i ^ 1] = 1; tarjan(v, fa); vis[i] = vis[i ^ 1] = 0; low[u] = min(low[u], low[v]); } else low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { dcc[u] = ++bcnt; while (stk[top] != u) dcc[stk[top--]] = bcnt; top--; } } int calc(int u, int v) { int x = find(u), y = find(v); if (x != y) return 0; if (dcc[u] != dcc[v]) return 1; if (f[u] == f[v]) return 3; return 2; } int main() { #ifndef ONLINE_JUDGE freopen("P4214.in", "r", stdin); #endif memset(h, -1, sizeof h); scanf("%d %d", &n, &m); // 节点数和管道数 for (int i = 1; i <= n; i++) p[i] = i; // 初始化并查集 for (int i = 1; i <= m; i++) { // 枚举每条边 int a, b; scanf("%d %d", &a, &b); add(a, b), add(b, a); // 并查集这是在干什么?记录点与点的连通性? int x = find(a), y = find(b); if (x != y) p[x] = y; } // base case初始化 for (int i = 1; i <= n; i++) f[i] = 1ll; // 为什么是m+1次呢? for (int x = 1; x <= m + 1; x++) { // tarjan初始化 memset(low, 0, sizeof low); memset(dfn, 0, sizeof dfn); ts = 0, bcnt = 0, top = 0; // 跑Tarjan,可能不连通 for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i, x << 1); for (int i = 1; i <= n; i++) f[i] = f[i] * mod + (LL)dcc[i]; } // 根据题意,计算最终的结果 int ans = 0; for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) ans += calc(i, j); // 输出 printf("%d\n", ans); return 0; }