Submission #272668

#TimeUsernameProblemLanguageResultExecution timeMemory
272668evpipisDuathlon (APIO18_duathlon)C++11
57 / 100
326 ms40052 KiB
#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 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...