一个图,n个点,n条边,没有重边和自环。
那么多出的一条边必定使他成为基环树。
要求去计算简单路径的个数。
简单路径:与方向无关的路径。
又因为在树上,两点的路径唯一确定,那么路径仅仅与起点与终点有关。
也就是C(2,n)这样。
但是如果路径经过环,那么中间经过环的部分就可以有两种走法。
也就是说答案=走过环的路径+没有走过环的路径
假设所有路径都过环,再减去树内的路径
通过拓扑排序和并查集的方式,将这个基环树划分为几个子树。
#include<bits/stdc++.h> #define inf 0x3f3f3f3f #define MAX 1000001 #define inf 0x3f3f3f3f #define ll long long #define MAX 1000001 const ll N = 2e5+7; const ll mod = 1e9+7; using namespace std; ll deg[N],cnt,q[N],fa[N],num[N],n; vector<int> G[N]; int find(int u){ return fa[u]==u?u:fa[u]=find(fa[u]); } void unite(int u,int v){ u=find(u),v=find(v); if(u==v) return ; fa[u]=v; num[v]+=num[u]; } int main(){ int t;scanf("%d",&t); while(t--){ scanf("%lld",&n); //初始化 cnt=0; for(int i=1;i<=n;++i){ G[i].clear(); num[i]=1;fa[i]=i;deg[i]=0; } for(int i=1;i<=n;++i){ int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); deg[u]++;deg[v]++; } //找根 for(int i=1;i<=n;++i) if(deg[i]==1) q[++cnt]=i; //划分出各个基环上的树 for(int i=1;i<=cnt;++i){ int u=q[i]; for(int j=0;j<G[u].size();++j){ int v=G[u][j]; unite(u,v); deg[v]--; if(deg[v]==1) q[++cnt]=v; } } ll ans=n*(n-1); for(int i=1;i<=n;++i){ if(i==fa[i]){ ans=ans-(1ll*num[i]*(num[i]-1)/2); } } printf("%lld\n",ans); } return 0; }