#include <cassert>
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
using ll = long long;
namespace orig {
vector<vector<int>> graph;
vector<int> tm;
vector<int> l;
int cur_tm = 0;
vector<vector<int>> components;
vector<bool> articulation;
stack<int> s;
void dfs(int const cur, int const par, int const start) {
l[cur] = tm[cur] = cur_tm;
cur_tm++;
s.push(cur);
for (int const& neigh : graph[cur]) {
if (neigh == par)
continue;
if (tm[neigh] == -1) {
dfs(neigh, cur, start);
if (l[neigh] >= tm[cur]) {
components.push_back({ cur });
articulation[cur] = cur != start || (cur == start && neigh != graph[start][0]);
while (s.top() != cur) {
components.back().push_back(s.top());
s.pop();
}
}
}
l[cur] = min(l[cur], l[neigh]);
}
}
}
namespace bct {
vector<vector<int>> graph;
vector<ll> sz;
vector<int> from_orig;
ll ans = 0;
vector<ll> subtree_sz;
vector<bool> done;
void dfs_sz(int const cur, int const par) {
subtree_sz[cur] = sz[cur];
done[cur] = true;
for (int const& neigh : graph[cur]) {
if (neigh == par)
continue;
dfs_sz(neigh, cur);
subtree_sz[cur] += subtree_sz[neigh];
}
}
void dfs_ans(int const cur, int const par, int const root) {
for (int const& neigh : graph[cur]) {
if (neigh == par)
continue;
dfs_ans(neigh, cur, root);
}
bool const articulation = cur >= orig::components.size();
// s, f in node
ans += sz[cur] * (sz[cur] - 1) * (sz[cur] - 2);
if (!articulation)
ans += graph[cur].size() * sz[cur] * (sz[cur] - 1);
// s in node, f in strict subtree or vice verca
ans += 2 * sz[cur] * (sz[cur] - 1) * (subtree_sz[cur] - sz[cur]);
if (!articulation)
ans += 2 * /* s: */ sz[cur] * /* f: */ (subtree_sz[cur] - sz[cur]) * /* c: */ ((ll)graph[cur].size() - 1);
// s and f in different subtrees
for (int const& neigh : graph[cur]) {
if (neigh == par)
continue;
ans += sz[cur] * subtree_sz[neigh] * (subtree_sz[cur] - sz[cur] - subtree_sz[neigh]);
if (!articulation)
ans += /* s: */ subtree_sz[neigh] * /* f: */ (subtree_sz[cur] - sz[cur] - subtree_sz[neigh]) * /* c: */ ((ll)graph[cur].size() - 2);
}
// s in subtree, f not in subtree or vice verca
ans += 2 * sz[cur] * (subtree_sz[cur] - 1) * (subtree_sz[root] - subtree_sz[cur]);
if (!articulation) {
// s in node, f not in subtree or vice verca
ans += 2 * /* s: */ sz[cur] * /* f: */ (subtree_sz[root] - subtree_sz[cur]) * /* c: */ ((ll)graph[cur].size() - 1);
// s in strict subtree, f not in subtree of vice verca
ans += 2 * /* s: */ (subtree_sz[cur] - sz[cur]) * /* f: */ (subtree_sz[root] - subtree_sz[cur]) * /* c: */ ((ll)graph[cur].size() - 2);
}
}
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
orig::graph.assign(n, {});
orig::tm.assign(n, -1);
orig::l.assign(n, -1);
orig::cur_tm = 0;
orig::components.clear();
orig::articulation.assign(n, false);
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
u--; v--;
orig::graph[u].push_back(v);
orig::graph[v].push_back(u);
}
for (int i = 0; i < n; i++) {
if (orig::tm[i] == -1) {
orig::dfs(i, -1, i);
#ifdef _DEBUG
assert(orig::s.top() == i);
assert(orig::s.size() == 1);
#endif
orig::s.pop();
}
}
bct::graph.assign(orig::components.size(), {});
bct::from_orig.resize(n);
for (int i = 0; i < n; i++) {
if (orig::articulation[i]) {
bct::from_orig[i] = bct::graph.size();
bct::graph.push_back({});
}
}
bct::sz.assign(bct::graph.size(), 0);
fill(bct::sz.begin() + orig::components.size(), bct::sz.end(), 1);
for (int component_i = 0; component_i < orig::components.size(); component_i++) {
auto const& component = orig::components[component_i];
for (int const& v : component) {
if (orig::articulation[v]) {
int const p = bct::from_orig[v];
int const q = component_i;
bct::graph[p].push_back(q);
bct::graph[q].push_back(p);
}
else
bct::sz[component_i]++;
}
}
bct::subtree_sz.assign(bct::graph.size(), 0);
bct::done.assign(bct::graph.size(), false);
for (int i = 0; i < orig::components.size(); i++) {
if (!bct::done[i]) {
bct::dfs_sz(i, -1);
bct::dfs_ans(i, -1, i);
}
}
#ifdef _DEBUG
for (int i = 0; i < bct::graph.size(); i++)
assert(bct::done[i]);
#endif
cout << bct::ans << "\n";
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |