战争游戏[tarjan]

Description
在这里插入图片描述

Input
在这里插入图片描述

Output
在这里插入图片描述

Sample Input
7 9
1 2
1 3
1 4
1 5
1 6
1 7
2 3
4 5
6 7

Sample Output
18
6
6
6
6
6
6

Data Constraint
在这里插入图片描述
.
.
.
.
.
分析
tarjan找割点直接计算即可。对于一个点,若它是割点,那么它的贡献即为删去这个点后不同联通块的size两两相乘的和再除以二,最后加上n-1,(代表以这个点为起点的种数)。若它不是割点,那么它的贡献就是n-1。注意计算两两联通块相乘的和时,考虑x的子树中有返祖边的情况。比如这个情况:n=4,m=4,(u,v)=(1,4),(2,3),(1,2),(2,4)。对于割点的答案应是5。

.
.
.
.
.
.
程序:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

int cnt=1,dfn[50100],low[50100],f[50100],ans[50100],head[200010],w[50100],n,m;

struct edge
{
	int next,to;
} a[200010];

void add(int x,int y)
{
	a[cnt].next=head[x];
	a[cnt].to=y;
	head[x]=cnt++;
}

void tarjan(int x)
{
	dfn[x]=low[x]=++cnt;
	w[x]=1;
	int sum=0;
	for (int i=head[x];i;i=a[i].next)
	{
		int u=a[i].to;
		if (dfn[u]==0)
		{
			tarjan(u);
			low[x]=min(low[x],low[u]);
			w[x]+=w[u];
			if (dfn[x]<=low[u])
			{
				f[x]=1;
				sum+=w[u];
				ans[x]+=w[u]*(n-w[u]-1);
			}
		} else low[x]=min(low[x],dfn[u]);
	}
	ans[x]+=sum*(n-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);
	}
	memset(f,false,sizeof(f));
	cnt=0;
	tarjan(1);
	for (int i=1;i<=n;i++)
		printf("%d
",ans[i]/2+n-1);
	return 0;
}
原文地址:https://www.cnblogs.com/YYC-0304/p/10458931.html