【题解】洛谷P3469 BLO-Blockade(tarjan 割点)

建好图后,我们可以通过dfs记录某一个点之后的子节点个数,并不断更新dfn和low值,如果low值大于等于dfn值(大于代表是一条链,等于代表是一个环),这样都会出现去掉该点后将图分成两部分的情况,所以我们将该点以下子节点个数累加,记录答案为对于每个y及y后的结点*(n-每个y及y后的结点),注意这么操作后会导致只统计要去掉那个点之后的所有结点到要去掉的那个点的距离,而答案我们还需要记录要去掉的那个点到剩下的所有节点(也就是n-1)与要去掉的那个点前面的结点到后面与该节点的乘积

说的太乱了。。。看代码吧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define ll long long
using namespace std;
const int maxn=1000010;
const int maxm=5000010;
int head[maxn],nnext[maxm*2],to[maxm*2];
int n,m,tot;
ll low[maxn],dfn[maxn],ind;
ll size[maxn],ans[maxn];
void add(int x,int y)
{
	tot++;
	nnext[tot]=head[x];
	head[x]=tot;
	to[tot]=y;
}
void dfs(int x,int fa)
{
	low[x]=dfn[x]=++ind;
	size[x]=1;
	ll sum=0;
	for(int i=head[x];i;i=nnext[i])
	{
		int y=to[i];
		if(y==fa) continue;
		if(dfn[y]==0)
		{
			dfs(y,x);
			size[x]+=size[y];
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x])
			{
				sum+=size[y];
				ans[x]+=size[y]*(n-size[y]);
			}
		}
		else
		{
			low[x]=min(low[x],low[y]);
		}
	}
	ans[x]+=n-1+(n-sum-1)*(sum+1);	
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)
	{
		printf("%lld\n",ans[i]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rem_Inory/article/details/81782850