Codeforces Round #686 (Div. 3) E. Number of Simple Paths Topological Sorting + Combinatorics

Meaning of the title : Give a Unicom graph with n points and n edges. Ask how many simple paths are there.
A simple path refers to a path that an edge passes through at most once.

Idea : First, this Unicom graph can be seen as a tree, and then an edge is added.
For a tree, any two points can be reached, the simple path is N * (N-1) / 2
and after considering adding an edge, it is easy to know that a tree, plus an edge, must form a ring .
Then we can consider the contribution that the more side will bring.

Insert picture description here
As shown in the figure above, taking each point on the ring as the root, it will be divided into three trees. For points in the same subtree, there is only one simple path from each point to any point in the subtree where it is located, and there are two paths to different subtrees.
So dfs once, process the size of the subtree with the point on the ring as the root.
1. For the points inside the blue, the contribution that can be more is the size of the blue subtree multiplied by the number of nodes in the green and red parts.
2. For the green part, the contribution that can be more is the size of the green subtree multiplied by the red subtree node. Because the point size is between blue and green, the blue part has already been calculated.

So the answer in the picture above is 10 * 9/2 = 45
and the contribution of more than 45 is 5 * 5 + 1 * 4 = 29
45 + 29 = 74

The nodes on the ring can be processed by topological sorting

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+50;
typedef long long ll;
vector<int> e[N];
bool vis[N];
int in[N],siz[N];
void dfs(int x,int f){
    
    
    siz[x]=1;
    for(auto y:e[x]){
    
    
        if(y==f || in[y]>1) continue;
        dfs(y,x);
        siz[x]+=siz[y];
    }
}
int main(){
    
    
    int T;cin>>T;
    while(T--){
    
    
        int n;cin>>n;
        for(int i=1;i<=n;i++) siz[i]=in[i]=0,e[i].clear();
        for(int i=1;i<=n;i++){
    
    
            int x,y;cin>>x>>y;
            e[x].push_back(y);
            e[y].push_back(x);
            in[x]++;
            in[y]++;
        }
        queue<int> que;
        for(int i=1;i<=n;i++){
    
    
            if(in[i]==1) que.push(i);
        }
        while(!que.empty()){
    
    
            int x=que.front();
            que.pop();
            for(auto y:e[x]){
    
    
                --in[y];
                if(in[y]==1) que.push(y);
            }
        }
        vector<int>a;
        ll ans=1ll*n*(n-1)/2;
        for(int i=1;i<=n;i++){
    
    
            if(in[i]>1){
    
    
                dfs(i,-1);
                a.push_back(siz[i]);
            }
        }
        for(auto i:a){
    
    
            ans+=1ll*i*(n-i);
            n-=i;
        }
        cout<<ans<<endl;
    }
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_43563669/article/details/110494962
Recommended