P3469 [POI2008]BLO-Blockade(割点+搜索树性质)

其实很容易看出来和割点有关

, 2 ( n 1 ) 如果某个点不是割点,去掉之后答案就是2(n-1)

, x , a 1 , a 1 , . . . a x 如果某个点是割点,去掉之后会分成x割连通块,记作a_1,a_1,...a_x

a 1 , ( n a 1 ) , a 1 ( n a 1 ) 对于a_1来说,到不了的点有(n-a_1),所以对答案贡献是a_1*(n-a_1)

a 2 a 2 ( n a 2 ) , a x a x ( n a x ) 对a_2来说是a_2*(n-a_2),对a_x来说是a_x*(n-a_x)

. . . 但是怎么计算连通块大小是个难题...

t a r j a n , d p 记住tarjan的搜索过程是一颗搜索树,可以按照树型dp的方法来计算子树大小

, ( n 1 ) 由于去掉了一个点,所以最后还要加(n-1)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e6+10;
int n,m,cut[maxn],siz[maxn],ans[maxn];
struct edge{
	int to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){
	d[++cnt]=(edge){v,head[u]},head[u]=cnt;
}
int low[maxn],dfn[maxn],id;
void tarjan(int u)
{
	low[u]=dfn[u]=++id;
	siz[u]=1;
	int flag=0,sumn=0;
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v=d[i].to;
		if( !dfn[v] )	
		{
			tarjan(v);
			siz[u]+=siz[v];
			low[u]=min( low[u],low[v] );	
			if( low[v]>=dfn[u] )//u是割点 
			{
				ans[u]+=siz[v]*( n-siz[v] );//v是子树 
				sumn+=siz[v];//总儿子数
				flag++;
				if( u!=1||flag>1 )	cut[u]=1; 
			}
		}
		else	low[u]=min( low[u],dfn[v] );
	}
	if( cut[u] )	ans[u]+=(n-sumn-1)*(sumn+1)+(n-1);
	else	ans[u]=2*(n-1);
}
signed main()
{
	cin >> n >> m;
	for(int i=1;i<=m;i++)
	{
		int l,r; cin >> l >> r;
		add(l,r); add(r,l);
	}
	tarjan(1);
	for(int i=1;i<=n;i++)
		cout << ans[i] << '\n';
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/108365839