This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
typedef pair<int, int> ii;
typedef long long ll;
const int len = 2e5+5;
int num[len], low[len], art[len], sz[len], vis[len], par[len], subtree[len];
int cnt_dfs, cnt_com, n, m;
ii edge[len];
vector<int> com[len], nex[len], stck;
vector<ii> adj[len];
// this dfs works fine because the graph is simple
// (no multiple edges or self loops)
void dfs(int u, int root = 0){
num[u] = low[u] = ++cnt_dfs;
int children = 0;
for (auto v: adj[u]){
if (!vis[v.se] && !num[v.fi]){
children++;
vis[v.se] = 1, stck.pb(v.se);
dfs(v.fi);
low[u] = min(low[u], low[v.fi]);
if (low[v.fi] >= num[u]){
cnt_com++;
art[u] = 1;
while (true){
int e = stck.back();
stck.pop_back();
com[cnt_com].pb(e);
if (e == v.se)
break;
}
}
}
else if (!vis[v.se] && num[v.fi]){
vis[v.se] = 1, stck.pb(v.se);
low[u] = min(low[u], num[v.fi]);
}
}
if (root)
art[u] = (children > 1);
//printf("finished dfs: u = %d, art = %d, num = %d, low = %d\n", u, art[u], num[u], low[u]);
}
void decompose(){
set<ii> mys;
for (int i = 1; i <= n; i++)
vis[i] = 0;
for (int i = 1; i <= cnt_com; i++){
/*
printf("component $%d:", i);
for (auto e: com[i])
printf(" (%d, %d)", edge[e].fi, edge[e].se);
printf("\n");
*/
for (auto e: com[i]){
int a = edge[e].fi, b = edge[e].se;
if (!vis[a] && !art[a])
vis[a] = 1, sz[i+n]++;
if (!art[b] && !vis[b])
vis[b] = 1, sz[i+n]++;
if (art[a] && !mys.count(mp(a, i+n))){
mys.insert(mp(a, i+n));
nex[a].pb(i+n);
nex[i+n].pb(a);
}
if (art[b] && !mys.count(mp(b, i+n))){
mys.insert(mp(b, i+n));
nex[b].pb(i+n);
nex[i+n].pb(b);
}
}
//printf("sz = %d\n", sz[i+n]);
}
}
void fix(int u){
/*
printf("u = %d\n", u);
if (art[u])
printf("i am articulation point\n");
else
printf("i am a 2-vertext cc\n");
*/
subtree[u] = 1;
if (!art[u])
subtree[u] = sz[u];
for (auto v: nex[u]){
if (v == par[u]) continue;
par[v] = u;
fix(v);
subtree[u] += subtree[v];
}
//printf("ins fix: u = %d, subtree = %d\n", u, subtree[u]);
}
ll solve(int u, int all){
//printf("u = %d, all = %d\n", u, all);
ll ans = 0;
for (auto v: nex[u])
if (v != par[u])
ans += solve(v, all);
ll sum = 0;
for (auto v: nex[u]){
int sub = subtree[v];
if (v == par[u])
sub = all-subtree[u];
//printf("%d -> %d, sub = %d\n", u, v, sub);
sum += sub;
}
//printf("u = %d, sum = %lld\n", u, sum);
if (art[u]){
for (auto v: nex[u]){
int sub = subtree[v];
if (v == par[u])
sub = all-subtree[u];
// two different subtrees
ans += sub*1LL*(sum-sub);
// same subtree - not all cases
ans += sz[v]*1LL*(sz[v]-1);
ans += 2*sz[v]*1LL*(sub-sz[v]);
}
}
else{
int mul = 0;
for (auto v: nex[u]){
int sub = subtree[v];
if (v == par[u])
sub = all-subtree[u];
mul += sub*1LL*(sum-sub);
}
for (auto v: nex[u]){
int sub = subtree[v];
if (v == par[u])
sub = all-subtree[u];
// two different subtrees
ans += sz[u]*1LL*sub*1LL*(sum-sub);
// 1 from my cc and one from a subtree
ans += 2*sz[u]*1LL*(sz[u]-1)*1LL*sub;
// center is adjacent art
ans += mul - 2*sub*1LL*(sum-sub);
}
// 2 from my cc
ans += sz[u]*1LL*(sz[u]-1)*1LL*(sz[u]-2);
}
return ans;
}
int main(){
scanf("%d %d", &n, &m);
for (int i = 0; i < m; i++){
int a, b;
scanf("%d %d", &a, &b);
adj[a].pb(mp(b, i));
adj[b].pb(mp(a, i));
edge[i] = mp(a, b);
}
for (int i = 1; i <= n; i++)
if (!num[i])
dfs(i, 1);
//printf("after dfs\n");
decompose();
//printf("after decompose\n");
//printf("cnt_com = %d\n", cnt_com);
ll ans = 0;
for (int i = 1; i <= n+cnt_com; i++)
if ((art[i] || i >= n+1) && !par[i])
fix(i), ans += solve(i, subtree[i]);
//printf("after solve\n");
printf("%lld\n", ans);
return 0;
}
/*
4 3
1 2
2 3
3 4
4 4
1 2
2 3
3 4
4 2
*/
Compilation message (stderr)
count_triplets.cpp: In function 'int main()':
count_triplets.cpp:185:10: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
185 | scanf("%d %d", &n, &m);
| ~~~~~^~~~~~~~~~~~~~~~~
count_triplets.cpp:188:14: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
188 | scanf("%d %d", &a, &b);
| ~~~~~^~~~~~~~~~~~~~~~~
# | 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... |