luogu P3469 [POI2008]BLO-Blockade 割点

#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 1000010, M =1000010;
inline int read()
{
	int x=0,t=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')t=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*t;
}
int n, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int stk[N], top;
int dcc_cnt;
int size[N];
bool cut[N];
//特判根节点
int root;
ll ans[N];
void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void tarjan(int u)
{
	dfn[u] = low[u] = ++ timestamp;
	size[u]=1;
	int sum1=0;
	int cnt = 0;
	//遍历邻边
	for (int i = h[u]; ~i; i = ne[i])
	{
		int j = e[i];
		//如果没被遍历过
		if (!dfn[j])
		{
			tarjan(j);
			size[u]+=size[j];
			low[u] = min(low[u], low[j]);
			if (dfn[u] <= low[j])
			{
				//当前分支到 除了这个分支外的点的 数量 
				ans[u]+=(ll)size[j]*(n-size[j]);
				sum1+=size[j];
				cnt ++ ;
				if (u != root || cnt > 1)
					cut[u] = true;
			}
		}
		else
			low[u] = min(low[u], dfn[j]);
	}
	//如果不是割点,那么就都还联通,少的就是当前点到其他所有,其他所有到当前点 
	if(cut[u]==0)
		ans[u]=2*(n-1);
	else
		//n-sum1-1 是其他所有,不包括当前点
		//sum1+1 是以这个点为根的子树,包括当前点
		//也就是,子树中的所有的点(包括当前点) 到不了其他的点
		//加上 其他店到不了当前点 
		ans[u]+=(ll)(n-sum1-1)*(sum1+1)+(n-1);
}

int main()
{
	//初始化
	idx = n = timestamp = top = dcc_cnt = 0;
	n=read(),m=read();
	memset(h, -1, sizeof h);
	memset(dfn, 0, sizeof dfn);
	memset(cut, 0, sizeof cut);
	//读边
	while (m -- )
	{
		int a=read(), b=read();
		add(a, b), add(b, a);
	}
	//遍历所有点
	for (root = 1; root <= n; root ++ )
		if (!dfn[root])
			tarjan(root);
	for(int i=1; i<=n; i++)
		cout<<ans[i]<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12922601.html