Submission #727764

#TimeUsernameProblemLanguageResultExecution timeMemory
727764SanguineChameleonDuathlon (APIO18_duathlon)C++17
100 / 100
118 ms47564 KiB
#include <bits/stdc++.h>
using namespace std;

void just_do_it();

int main() {
	#ifdef KAMIRULEZ
		freopen("kamirulez.inp", "r", stdin);
		freopen("kamirulez.out", "w", stdout);
	#endif
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	just_do_it();
	return 0;
}

const int maxn = 2e5 + 20;
bool flag[maxn];
int high[maxn];
int depth[maxn];
int cnt[maxn];
int cnt_sum1[maxn];
long long cnt_sum2[maxn];
bool art[maxn];
vector<int> adj[maxn];
vector<int> adj_tree[maxn];
vector<int> ch[maxn];
long long res;
int color_cnt;

void dfs1(int u, int par) {
	flag[u] = true;
	high[u] = depth[u];
	for (auto v: adj[u]) {
		if (v == par) {
			continue;
		}
		if (!flag[v]) {
			depth[v] = depth[u] + 1;
			ch[u].push_back(v);
			dfs1(v, u);
			high[u] = min(high[u], high[v]);
		}
		else {
			high[u] = min(high[u], depth[v]);
		}
	}
}

void dfs2(int u, int cur_color, bool root = false) {
	for (auto v: ch[u]) {
		if (high[v] >= depth[u] && (!root || (int)ch[u].size() >= 2)) {
			art[u] = true;
			color_cnt++;
			adj_tree[u].push_back(color_cnt);
			adj_tree[color_cnt].push_back(u);
			dfs2(v, color_cnt);
		}
		else {
			dfs2(v, cur_color);
		}
	}
	if (art[u]) {
		adj_tree[u].push_back(cur_color);
		adj_tree[cur_color].push_back(u);
	}
	else {
		cnt[cur_color]++;
	}
}

void dfs3(int u, int par) {
	cnt_sum1[u] = cnt[u];
	cnt_sum2[u] = 0;
	for (auto v: adj_tree[u]) {
		if (v != par) {
			dfs3(v, u);
			cnt_sum1[u] += cnt_sum1[v];
			cnt_sum2[u] += 1LL * cnt_sum1[v] * cnt_sum1[v];
		}
	}
}

long long ways1(int u) {
	return 1LL * cnt_sum1[u] * cnt_sum1[u] - cnt_sum2[u] - 1LL * cnt[u] * cnt[u] - 1LL * cnt[u] * (cnt_sum1[u] - cnt[u]) * 2;
}

long long ways2(int u) {
	return 1LL * cnt_sum1[u] * cnt_sum1[u] - cnt_sum2[u] - cnt[u];
}

void dfs4(int u, int par) {
	if (art[u]) {
		res += ways1(u);
		for (auto v: adj_tree[u]) {
			res += ways2(v);
		}
	}
	else {
		res += 1LL * cnt[u] * ways1(u);
		res += 1LL * cnt[u] * (cnt[u] - 1) * (cnt_sum1[u] - cnt[u]) * 2;
		res += 1LL * cnt[u] * (cnt[u] - 1) * (cnt[u] - 2);
	}
	for (auto v: adj_tree[u]) {
		if (v != par) {
			cnt_sum1[u] -= cnt_sum1[v];
			cnt_sum2[u] -= 1LL * cnt_sum1[v] * cnt_sum1[v];
			cnt_sum1[v] += cnt_sum1[u];
			cnt_sum2[v] += 1LL * cnt_sum1[u] * cnt_sum1[u];
			dfs4(v, u);
			cnt_sum1[v] -= cnt_sum1[u];
			cnt_sum2[v] -= 1LL * cnt_sum1[u] * cnt_sum1[u];
			cnt_sum1[u] += cnt_sum1[v];
			cnt_sum2[u] += 1LL * cnt_sum1[v] * cnt_sum1[v];
		}
	}
}

void solve(int root) {
	dfs1(root, -1);
	dfs2(root, ++color_cnt, true);
	dfs3(color_cnt, -1);
	dfs4(color_cnt, -1);
}

void just_do_it() {
	int n, m;
	cin >> n >> m;
	color_cnt = n;
	for (int i = 1; i <= n; i++) {
		cnt[i] = 1;
	}
	for (int i = 0; i < m; i++) {
		int u, v;
		cin >> u >> v;
		adj[u].push_back(v);
		adj[v].push_back(u);
	}
	for (int i = 1; i <= n; i++) {
		if (!flag[i]) {
			solve(i);
		}
	}
	cout << res;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...