圆方图(铁人两项)

#include<bits/stdc++.h>
using namespace std;
const int MM=400005;
int dfn[MM],low[MM],dfc,cnt,in[MM],tot,v[MM],vis[MM],siz[MM],n,m,V,U;
long long ans;
int stk[MM],tp;
vector<int> e[MM],t[MM];
stack<int> s;
void tarjan(int now)///建立圆方树 
{
	dfn[now]=low[now]=++dfc;
	stk[++tp]=now;
	++tot;
	for(int i=0;i<e[now].size();i++)
	{
		int to=e[now][i];
		//cout<<"qwq"<<' '<<now<<' '<<to<<endl;
		if(!dfn[to])
		{
			//cout<<"in"<<' '<<to<<endl;
			tarjan(to);
			//cout<<"out"<<' '<<now<<' '<<to<<' '<<low[to]<<endl;
			low[now]=min(low[now],low[to]);
			if(low[to]==dfn[now])///now就是桥 
			{
				cnt++;///方点+1 
				for(int x=0;x!=to;--tp)///由于桥可能同时在多个双连通分量内,所以now不出栈 
				{
					x=stk[tp];
					v[cnt]++;
					t[cnt].push_back(x);
					t[x].push_back(cnt);///连接方点和圆点 
				}
				t[now].push_back(cnt);
				t[cnt].push_back(now); 
				v[cnt]++;
			} 
		}
		else ///由于是双向边,此时to[i]必然是i的父节点,根据low的定义无需考虑to[i]。 
			low[now]=min(low[now],dfn[to]);	
	}
}
void dfs(int now,int fa)
{
	siz[now]=(now<=n);
	for(int i=0;i<t[now].size();i++)
	{
		if(t[now][i]==fa)
			continue;
		dfs(t[now][i],now);
		ans+=2ll*v[now]*siz[now]*siz[t[now][i]];
		siz[now]+=siz[t[now][i]];
	}
	ans+=2ll*v[now]*siz[now]*(tot-siz[now]); 
}
int main()
{
	cin>>n>>m;
	cnt=n;
	for(int i=1;i<=n;i++)
		v[i]=-1;
	for(int i=1;i<=m;i++)
	{
		cin>>U>>V;
		e[U].push_back(V);
		e[V].push_back(U);
	} 
	for(int i=1;i<=n;i++)	
		if(!dfn[i])
		{
			tot=0;
			tarjan(i);
			tp--;
			dfs(i,0);
		}
	cout<<ans;
	return 0;
}
posted @ 2022-01-10 16:37  T_X蒻  阅读(40)  评论(0编辑  收藏  举报