Submission #1213299

#TimeUsernameProblemLanguageResultExecution timeMemory
1213299spike1236Duathlon (APIO18_duathlon)C++20
0 / 100
1096 ms31660 KiB
#include <bits/stdc++.h>
using namespace std;
static const int MOD = 1000000007;

inline long long modMul(long long a, long long b) {
    return (a % MOD) * (b % MOD) % MOD;
}
inline long long modAdd(long long a, long long b) {
    a += b;
    if (a >= MOD) a -= MOD;
    return a;
}

long long choose3(long long n) {
    if (n < 3) return 0;

    long long x = ((n % MOD) * ((n - 1) % MOD)) % MOD;
    x = (x * ((n - 2) % MOD)) % MOD;

    return (x * 166666668LL) % MOD;
}

int N, M;
vector<vector<int>> adj;      
vector<int> disc, low, parent;
vector<bool> isCut;
int timerDFS;
stack<pair<int,int>> edgeStack; 

vector<vector<int>> biconnComp; 

vector<vector<int>> compVerts;

vector<vector<int>> blockCutAdj;  

int numComp; 
int cutOffset;

vector<vector<long long>> cutSubtreeSizes;

void dfsBCC(int u) {
    disc[u] = low[u] = ++timerDFS;
    int children = 0;
    for (int v : adj[u]) {
        if (disc[v] == 0) {
            parent[v] = u;
            children++;

            edgeStack.push({u,v});
            dfsBCC(v);
            low[u] = min(low[u], low[v]);

            bool rootCase = (parent[u] == 0 && children > 1);
            bool nonRootCase = (parent[u] != 0 && low[v] >= disc[u]);
            if (rootCase || nonRootCase) {
                isCut[u] = true;

                vector<int> thisComp;
                while (true) {
                    auto e = edgeStack.top(); 
                    edgeStack.pop();
                    int x = e.first, y = e.second;
                    thisComp.push_back(x);
                    thisComp.push_back(y);
                    if (x == u && y == v) break;
                }

                sort(thisComp.begin(), thisComp.end());
                thisComp.erase(unique(thisComp.begin(), thisComp.end()), thisComp.end());
                biconnComp.push_back(thisComp);
            }
        }
        else if (v != parent[u] && disc[v] < disc[u]) {

            low[u] = min(low[u], disc[v]);
            edgeStack.push({u,v});
        }
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

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

    disc.assign(N+1, 0);
    low.assign(N+1, 0);
    parent.assign(N+1, 0);
    isCut.assign(N+1, false);

    timerDFS = 0;

    for(int i = 1; i <= N; i++){
        if (disc[i] == 0) {
            dfsBCC(i);

            if (!edgeStack.empty()) {
                vector<int> thisComp;
                while (!edgeStack.empty()) {
                    auto e = edgeStack.top();
                    edgeStack.pop();
                    thisComp.push_back(e.first);
                    thisComp.push_back(e.second);
                }
                sort(thisComp.begin(), thisComp.end());
                thisComp.erase(unique(thisComp.begin(), thisComp.end()), thisComp.end());
                biconnComp.push_back(thisComp);
            }
        }
    }

    numComp = (int)biconnComp.size();
    cutOffset = numComp;  

    blockCutAdj.assign(numComp + N + 5, {});
    for(int i = 0; i < numComp; i++){

        for(int v : biconnComp[i]){
            if (isCut[v]) {
                int blockNode = i + 1;
                int cutNode = cutOffset + v;
                blockCutAdj[blockNode].push_back(cutNode);
                blockCutAdj[cutNode].push_back(blockNode);
            }
        }
    }

    cutSubtreeSizes.assign(N+1, {});
    vector<bool> visitedBC(numComp + N + 5, false);

    for(int v = 1; v <= N; v++){
        if (!isCut[v]) continue;

        int cutNodeV = cutOffset + v;
        visitedBC[cutNodeV] = true;

        for(int blockNode : blockCutAdj[cutNodeV]){
            if (visitedBC[blockNode]) continue;

            long long subtreeCount = 0;
            stack<int> stk;
            stk.push(blockNode);
            visitedBC[blockNode] = true;

            while(!stk.empty()){
                int x = stk.top();
                stk.pop();
                if (x <= numComp) {

                    int compIdx = x - 1;

                    int countInComp = (int)biconnComp[compIdx].size();

                    if (binary_search(biconnComp[compIdx].begin(), biconnComp[compIdx].end(), v)) {
                        countInComp--;
                    }
                    subtreeCount += countInComp;
                } else {

                    int u = x - cutOffset;
                    subtreeCount += 1;
                }

                for(int y : blockCutAdj[x]){
                    if (!visitedBC[y]) {
                        visitedBC[y] = true;
                        stk.push(y);
                    }
                }
            }

            cutSubtreeSizes[v].push_back(subtreeCount);
        }

        queue<int> q;
        visitedBC[cutNodeV] = false;
        for(int blockNode : blockCutAdj[cutNodeV]) {
            if (visitedBC[blockNode]) {

                q.push(blockNode);
                visitedBC[blockNode] = false;
            }
        }
        while(!q.empty()){
            int x = q.front(); q.pop();
            for(int y : blockCutAdj[x]){
                if (visitedBC[y]) {
                    visitedBC[y] = false;
                    q.push(y);
                }
            }
        }
    }

    long long totalBad = 0;
    for(int v = 1; v <= N; v++){
        if (!isCut[v]) continue;
        auto &sizes = cutSubtreeSizes[v];
        long long sumSz = 0;
        for(auto &x : sizes) sumSz += x;
        long long rem = (long long)(N - 1) - sumSz;
        if (rem > 0) sizes.push_back(rem);

        int k = (int)sizes.size();

        for(int i = 0; i < k; i++){
            for(int j = i + 1; j < k; j++){
                long long s_i = sizes[i];
                long long s_j = sizes[j];
                long long others = (long long)(N - 1) - s_i - s_j;
                long long contrib = ((s_i % MOD) * (s_j % MOD)) % MOD;
                contrib = ( (contrib % MOD) * (others % MOD) ) % MOD;
                totalBad = (totalBad + contrib) % MOD;
            }
        }
    }

    long long totalTriples = choose3(N);
    long long answer = ( (totalTriples - totalBad) % MOD + MOD ) % MOD;
    cout << answer << "\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...