제출 #408674

#제출 시각아이디문제언어결과실행 시간메모리
408674RGBB철인 이종 경기 (APIO18_duathlon)C++14
100 / 100
263 ms69708 KiB
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>pp;
const int MAXN=2*1e5;
int n,m;
ll ans;
//biconnection stuffs
int t,cnt,low[MAXN],dist[MAXN],parent[MAXN];
bool vis[MAXN];
vector<int>adj[MAXN];
unordered_set<int>bcc[MAXN];
stack<pp>stk;
void dfs(int p){
    vis[p]=true;
    low[p]=t;
    dist[p]=t;
    t++;
    int children=0;
    for(int i:adj[p]){
        if(!vis[i]){
            children++;
            parent[i]=p;
            stk.push({p,i});
            dfs(i);
            low[p]=min(low[p],low[i]);
            if((dist[p]==0&&children>1)||(dist[p]>0&&low[i]>=dist[p])){
                while(true){
                    bcc[cnt].insert(stk.top().first);
                    bcc[cnt].insert(stk.top().second);
                    if(stk.top()==make_pair(p,i)){
                        stk.pop();
                        break;
                    }
                    stk.pop();
                }
                cnt++;
            }
        }
        else if(i!=parent[p]){
            low[p]=min(low[p],dist[i]);
            if(dist[i]<dist[p])stk.push({p,i});
        }
    }
}
unordered_set<int>art;
void dfs2(int p){
    vis[p]=true;
    dist[p]=t;
    low[p]=t;
    t++;
    int children=0;
    for(int i:adj[p]){
        if(i==parent[p])continue;
        if(vis[i])low[p]=min(low[p],dist[i]);
        else{
            parent[i]=p;
            dfs2(i);
            low[p]=min(low[p],low[i]);
            if(low[i]>=dist[p]&&parent[p]!=-1){
                art.insert(p);
                children++;
            }
        }
    }
    if(parent[p]==-1&&children>1)art.insert(p);
}
int num,si[MAXN],group[MAXN];
bool type[MAXN];
vector<int>edge[MAXN];
void construct(int p){
    vis[p]=true;
    queue<int>q;
    q.push(p);
    while(!q.empty()){
        int cur=q.front();
        q.pop();
        for(auto&i:edge[cur]){
            if(vis[i])continue;
            parent[i]=cur;
            vis[i]=true;
            q.push(i);
        }
    }
}
vector<int>roots;
ll freq[MAXN][2],dp[MAXN];
ll below(int p){
    for(auto&i:edge[p])if(i!=parent[p])freq[p][0]+=below(i)+si[i];
    return freq[p][0];
}
void above(int p){
    for(auto&i:edge[p]){
        if(i==parent[p])continue;
        freq[i][1]=freq[p][1]+si[p]+freq[p][0]-freq[i][0]-si[i];
        above(i);
    }
}
void solve(){
    for(int i=0;i<num;i++){
        if(type[i]){
            for(int y:edge[i]){
                ll a;
                if(y!=parent[i])a=freq[y][0]+1;
                else a=freq[i][1];
                ans-=si[i]*a*(a-1);
                dp[i]+=a*(a-1);
            }
        }
    }
    for(int i=0;i<num;i++){
        if(!type[i]){
            for(int y:edge[i]){
                if(y!=parent[i])ans-=dp[y]-freq[y][1]*(freq[y][1]-1);
                else ans-=dp[y]-(freq[i][0]+si[i])*(freq[i][0]+si[i]-1);
            }
        }
    }
}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    //input
    cin>>n>>m;
    for(int i=0;i<m;i++){
        int a,b;
        cin>>a>>b;
        adj[a-1].push_back(b-1);
        adj[b-1].push_back(a-1);
    }
    //biconnect
    t=0;
    cnt=0;
    memset(low,0,sizeof(low));
    memset(dist,0,sizeof(dist));
    memset(parent,-1,sizeof(parent));
    memset(vis,false,sizeof(vis));
    for(int i=0;i<n;i++)if(!vis[i])dfs(i);
    if(!stk.empty()){
        while(!stk.empty()){
            bcc[cnt].insert(stk.top().first);
            bcc[cnt].insert(stk.top().second);
            stk.pop();
        }
        cnt++;
    }
    //articulation points
    memset(vis,false,sizeof(vis));
    for(int i=0;i<n;i++){
        if(!vis[i]){
            t=0;
            parent[i]=-1;
            dfs2(i);
        }
    }
    memset(vis,false,sizeof(vis));
    for(int i=n-1;i>=0;i--){
        if(!vis[i]){
            t=0;
            parent[i]=-1;
            dfs2(i);
        }
    }
    //construct forest nodes
    num=0;
    memset(si,0,sizeof(si));
    for(auto&i:art){
        group[i]=num;
        type[num]=false;
        si[num]=1;
        num++;
    }
    for(int i=0;i<cnt;i++){
        type[num]=true;
        for(auto&y:bcc[i]){
            if(art.find(y)!=art.end()){
                edge[num].push_back(group[y]);
                edge[group[y]].push_back(num);
            }
            else si[num]++;
        }
        num++;
    }
    //find roots and construct trees
    memset(vis,false,sizeof(vis));
    memset(parent,-1,sizeof(parent));
    for(int i=0;i<num;i++){
        if(!vis[i]){
            roots.push_back(i);
            construct(i);
        }
    }
    //tree dp
    ans=0;
    memset(freq,0,sizeof(freq));
    memset(dp,0,sizeof(dp));
    for(int i:roots){
        below(i);
        above(i);
        ll a=freq[i][0]+si[i];
        ans+=a*(a-1)*(a-2);
    }
    solve();
    //output answer
    cout<<ans<<"\n";
}
#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...