【算法】【图论】【强连通分量】】

0 阅读1分钟

atcoder.jp/contests/ty…

#include <bits/stdc++.h>  
using namespace std;  
using ll=long long;  
const int N=1<<18;  
int n,m;int a[N],b[N];  
bool us[N];  
vector<int>g[N];  
vector<int>h[N];  
vector<int>I;  
ll cnts;  
//记录后序遍历序列  
void dfs(int pos){  
    us[pos]=true;  
    for(int i:g[pos]){  
        if(!us[i])dfs(i);  
    }I.push_back(pos);  
}  
void dfs2(int pos){//反图  
    us[pos]=true;  
    cnts++;  
    for(int i:h[pos]){if(!us[i])dfs2(i);}  
}  
int main(){  
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);  
    cin>>n>>m;  
    for(int i=1;i<=m;i++){  
        cin>>a[i]>>b[i];  
        g[a[i]].push_back(b[i]);  
        h[b[i]].push_back(a[i]);  
    }for(int i=1;i<=n;i++){  
        if(!us[i])dfs(i);  
    }ll ans=0;  
    reverse(I.begin(),I.end());  
    fill(us,us+n+1,false);  
    for(int i:I){  
        if(us[i])continue;  
        cnts=0;  
        dfs2(i);  
        ans+=cnts*(cnts-1ll)/2ll;  
    }  
    cout<<ans;  
}

思路

原图 DFS: 能到达别人的点会后结束 反图 DFS: 从后结束的点开始搜 只能搜到互相可达的点 刚好就是一个强连通分量!