圆方图(铁人两项)

#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;
}

原文链接: https://www.cnblogs.com/29taorz/p/15785049.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    圆方图(铁人两项)

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/184609

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 上午10:45
下一篇 2023年2月12日 上午10:46

相关推荐