传送门
完全没想到圆方树orz……
我们先考虑建出这个图的圆方树,如果把方点的权值设为这个点双的大小,圆点的权值为\(-1\),那么起点\(s\)终点\(f\)的方案数就是这条路径上的权值总和,这样的话就可以做到\(O(n^2)\)
然后考虑用dfs优化,即计算每个点被经过了几次,那么就可以做到\(O(n)\)了
顺便注意起点和终点互换属于不同的方案,所以不要漏了
//minamoto
#include
#define ll long long
#define fp(i,a,b) for(register int i=a,I=b+1;iI;--i)
#define go(G,u) for(register int i=G.head[u],v=G.e[i].v;i;i=G.e[i].nx,v=G.e[i].v)
using namespace std;
inline int max(const int &x,const int &y){return x>y?x:y;}
inline int min(const int &x,const int &y){return x'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
const int N=5e5+5;
struct eg{int v,nx;};
struct Gr{
eg e[N];int head[N],tot;
inline void add(int u,int v){e[++tot]={v,head[u]},head[u]=tot;}
}G,T;
int n,m,tim,tot,x,u,v,top,dfn[N],low[N],st[N],val[N],sz[N],sum;ll ans;
void tarjan(int u){
dfn[u]=low[u]=++tim,st[++top]=u;
sz[u]=1,val[u]=-1;
go(G,u)if(dfn[v])low[u]=min(low[u],dfn[v]);
else{
tarjan(v),low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
T.add(u,++tot),val[tot]=1;
do{
x=st[top--],T.add(tot,x);
sz[tot]+=sz[x],++val[tot];
}while(x!=v);
sz[u]+=sz[tot];
}
}
}
void dfs(int u){
if(u<=n)ans+=1ll*(sum-1)*val[u];
ans+=1ll*(sum-sz[u])*sz[u]*val[u];
go(T,u)ans+=1ll*(sum-sz[v])*sz[v]*val[u],dfs(v);
}
int main(){
// freopen("testdata.in","r",stdin);
tot=n=read(),m=read();
while(m--)u=read(),v=read(),G.add(u,v),G.add(v,u);
fp(i,1,n)if(!dfn[i])tarjan(i),sum=sz[i],dfs(i);
printf("%lld\n",ans);return 0;
}