E. Number of Simple Paths (reverse thinking + base ring tree)

https://codeforces.com/contest/1454/problem/E


Reference: https://frozenguardian.blog.csdn.net/article/details/110137634?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog- BlogCommendFromMachineLearnPai2-1.control

The main idea of ​​the topic: Given a base ring tree with n points, the number of paths with length greater than or equal to 1.

Idea: For all paths (x, y) can be divided into the following two cases to consider:

  1. The path does not go through the edges on the ring: at this time the path between point x and point y is unique
  2. The path will pass through the edges on the ring: at this time there are two paths between point x and point y, one is going clockwise along the ring and the other is going counterclockwise along the ring

The opposite is true. First, assume that all paths will pass through the edges on the ring, and then count how many point pairs (x, y) are paths between that do not need to pass through the edges on the ring and subtract their contribution.

(Each point and its remaining points will be counted as one more)

The specific implementation is to run out of the ring first. This can be run using topology or dfs, and then treat the entire ring as the root node, so that the entire graph can be regarded as a tree, and run out of all children with the ring as the "root" node. The size of the tree is sufficient, because each subtree is independent of each other, and there must be only one path between two points in each subtree


#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+100;
typedef long long LL;
bool loop[maxn],vis[maxn];
LL fa[maxn],dfn[maxn],id;
vector<LL>g[maxn];
void init(LL n){
    id=0;
    for(LL i=0;i<n+10;i++){
        g[i].clear();
        vis[i]=loop[i]=0;
        fa[i]=dfn[i]=0;
    }
}
void get_loop(LL u){
    dfn[u]=++id;
    for(LL i=0;i<g[u].size();i++){
        LL v=g[u][i];
        if(dfn[v]){
            if(dfn[v]<dfn[u]) continue;
            while(v!=fa[u]){
                loop[v]=true;
                v=fa[v];
            }
        }
        else{
            fa[v]=u;
            get_loop(v);
        }
    }
}
LL dfs(LL u){
    vis[u]=true;
    LL ans=1;
    for(LL i=0;i<g[u].size();i++){
        LL v=g[u][i];
        if(vis[v]||loop[v]) continue;
        ans+=dfs(v);
    }
    return ans;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL t;cin>>t;
  while(t--){
    LL n;cin>>n;
    init(n);
    for(LL i=1;i<=n;i++){
        LL u,v;cin>>u>>v;
        g[u].push_back(v);g[v].push_back(u);
    }
    get_loop(1);
    LL ans=n*(n-1);
    for(LL i=1;i<=n;i++){
        if(loop[i]){
            LL k=dfs(i);///带上了基环点
            k=max(k,(LL)0);
            ans-=k*(k-1)/2;
        }
    }
    cout<<ans<<endl;
  }
return 0;
}

 

Guess you like

Origin blog.csdn.net/zstuyyyyccccbbbb/article/details/113092029