제출 #1353564

#제출 시각아이디문제언어결과실행 시간메모리
1353564DanerZein철인 이종 경기 (APIO18_duathlon)C++20
100 / 100
67 ms31352 KiB
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int N, M;
    cin >> N >> M;

    vector<vector<int>> g(N + 1);
    for (int i = 0; i < M; i++) {
        int u, v; cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    // ── Step 1: Find BCCs (iterative Tarjan) ─────────────────────────────────
    vector<int> disc(N + 1, -1), low(N + 1, 0);
    int timer = 0;
    vector<int> vstk;
    vector<vector<int>> bccs;
    vector<tuple<int,int,int>> call_stack;

    for (int start = 1; start <= N; start++) {
        if (disc[start] != -1) continue;
        disc[start] = low[start] = timer++;
        vstk.push_back(start);
        call_stack.push_back({start, -1, 0});

        while (!call_stack.empty()) {
            auto& [u, p, idx] = call_stack.back();
            if (idx < (int)g[u].size()) {
                int v = g[u][idx++];
                if (v == p) continue;
                if (disc[v] == -1) {
                    disc[v] = low[v] = timer++;
                    vstk.push_back(v);
                    call_stack.push_back({v, u, 0});
                } else {
                    low[u] = min(low[u], disc[v]);
                }
            } else {
                call_stack.pop_back();
                if (!call_stack.empty()) {
                    auto& [pu, pp, pi] = call_stack.back();
                    low[pu] = min(low[pu], low[u]);
                    if (low[u] >= disc[pu]) {
                        vector<int> comp;
                        while (vstk.back() != u) { comp.push_back(vstk.back()); vstk.pop_back(); }
                        comp.push_back(u); vstk.pop_back();
                        comp.push_back(pu);
                        sort(comp.begin(), comp.end());
                        comp.erase(unique(comp.begin(), comp.end()), comp.end());
                        bccs.push_back(move(comp));
                    }
                }
            }
        }
    }

    int num_bcc = (int)bccs.size();
    int n_bct = N + num_bcc;

    // ── Step 2: Build BCT ────────────────────────────────────────────────────
    // Vertex nodes 0..N-1, block nodes N..N+B-1
    vector<vector<int>> bct(n_bct);
    for (int b = 0; b < num_bcc; b++) {
        int bn = N + b;
        for (int v : bccs[b]) {
            bct[v-1].push_back(bn);
            bct[bn].push_back(v-1);
        }
    }

    // ── Step 3: DFS on BCT ───────────────────────────────────────────────────
    vector<ll>  sub(n_bct, 0);
    vector<int> par_bct(n_bct, -1);
    vector<int> comp_id(n_bct, -1);
    vector<ll>  comp_sz;
    vector<int> order;
    order.reserve(n_bct);

    for (int root = 0; root < n_bct; root++) {
        if (comp_id[root] != -1 || bct[root].empty()) continue;
        int cid = (int)comp_sz.size();
        ll csz = 0;
        stack<int> dfs;
        dfs.push(root);
        comp_id[root] = cid;
        while (!dfs.empty()) {
            int u = dfs.top(); dfs.pop();
            order.push_back(u);
            if (u < N) csz++;
            for (int v : bct[u])
                if (comp_id[v] == -1) {
                    comp_id[v] = cid;
                    par_bct[v] = u;
                    dfs.push(v);
                }
        }
        comp_sz.push_back(csz);
    }

    for (int i = (int)order.size()-1; i >= 0; i--) {
        int u = order[i];
        sub[u] = (u < N) ? 1 : 0;
        for (int v : bct[u])
            if (v != par_bct[u])
                sub[u] += sub[v];
    }

    // ── Step 4: Precompute per-block aggregates ───────────────────────────────
    // For each block node B:
    //   child_sum2[B] = sum over child vertex nodes v of B: sub[v]*(sub[v]-1)
    //   up_sz[B]      = comp_sz - sub[B]     (size going "upward" through B)
    //   up_contrib[B] = up_sz * (up_sz - 1)  (only valid if B has a parent)
    vector<ll> child_sum2(n_bct, 0);
    vector<ll> up_contrib(n_bct, 0);

    for (int B = N; B < n_bct; B++) {
        ll cid = comp_id[B];
        ll up_sz = comp_sz[cid] - sub[B];
        up_contrib[B] = (par_bct[B] != -1) ? up_sz * (up_sz - 1) : 0;
        for (int v : bct[B])
            if (par_bct[v] == B)          // v is a child of B
                child_sum2[B] += sub[v] * (sub[v] - 1);
    }

    // ── Step 5: Sum contributions ─────────────────────────────────────────────
    ll ans = 0;

    for (int c = 0; c < N; c++) {
        if (bct[c].empty()) continue;
        ll S = comp_sz[comp_id[c]] - 1;
        if (S < 2) continue;

        ll invalid = 0;

        for (int B : bct[c]) {
            if (par_bct[B] == c) {
                // Case A: c is the PARENT of block B in BCT
                // All vertices of B other than c are children of B → use child_sum2
                // But child_sum2[B] includes sub[?]*(sub[?]-1) for all children of B.
                // None of B's children is c (c is B's parent, not child).
                // So invalid_from_B = child_sum2[B]   (no need to subtract c)
                invalid += child_sum2[B];
            } else {
                // Case B: c is a CHILD of block B in BCT (par_bct[c] == B)
                // Grandchildren through B (for c) are:
                //   - Other children of B (v != c): contribute sub[v]*(sub[v]-1)
                //     = child_sum2[B] - sub[c]*(sub[c]-1)
                //   - The upward direction (through par_bct[B]): contribute up_contrib[B]
                invalid += child_sum2[B] - sub[c] * (sub[c] - 1) + up_contrib[B];
            }
        }

        ans += S * (S - 1) - invalid;
    }

    cout << ans << "\n";
    return 0;
}
#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...