- 题意:给出一个基环树,求图中简单路径数。
- 思路:考虑一个简单环,任意两点间的简单路径数为2,其总简单路径数为n*(n-1);因此基环树中的简单路径数就是n*(n-1)-多算的路径数。现在考虑多算的路径是那些:整个图可以看成是一个环,环上的每个点挂着一棵树,由于环上任意两点间的简单路径数为2,不同树上任意两点间简单路径数为2,因此多算的部分只是所有树上的简单路径数,大小为siz(i)的树简单路径数为siz(i)*(siz(i)-1)/2。
- 模拟赛上的思路是分别求,求环上点间的路径数,单棵树上的路径树,不同树上点间路径数,思路没问题,式子有小毛病。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=2e5+5;
int t,last[maxn],col[maxn],nd,cnt,bloc=1,cnt0;
long long num[maxn],ans,ans0[maxn],n;
bool inq[maxn],coll;
struct edge{
int v,next;
}e[maxn*2];
void add(int u,int v)
{
e[++cnt].v=v;
e[cnt].next=last[u];
last[u]=cnt;
}
void dfs(int u,int fa)
{
inq[u]=1;
for(int i=last[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==fa) continue;
if(inq[v])
{
nd=v;
coll=1;
col[u]=col[v]=1;
num[1]++;
return ;
}
dfs(v,u);
if(coll)
{
num[1]++;
col[u]=1;
coll=(u==nd?0:1);
return ;
}
}
}
int dfs2(int u,int fa)
{
int ndpw=0;
for(int i=last[u];i;i=e[i].next)
{
int v=e[i].v;
if(col[v]==1||v==fa) continue;
col[v]=bloc;
num[bloc]++;
ndpw+=dfs2(v,u);
}
ndpw++;
return ndpw;
}
void init()
{
coll=0;
for(int i=1;i<=n;i++)
last[i]=col[i]=inq[i]=num[i]=ans0[i]=0;
cnt0=ans=cnt=nd=0;
bloc=1;
}
int main()
{
cin>>t;
while(t--)
{
scanf("%lld",&n);
for(int i=1,u,v;i<=n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,0);
long long tmp0=0;
for(int i=1;i<=n;i++)
{
if(col[i]==1)
{
bloc++;
dfs2(i,0);
if(num[bloc])
tmp0+=(num[bloc]+1)*num[bloc]/2;
}
}
cout<<(n*(n-1))-tmp0<<endl;
init();
}
return 0;
}