bzoj1123:[POI2008]BLO

传送门

提示:被删掉的点也要算点对,((i,j))((j,i))是不同的点对

显然找出割点就行了,记下size,对于各子树统计一下答案
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
void read(int &x) {
	char ch; bool ok;
	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
const int maxn=1e5+10;
int n,m,size[maxn],tot,now,pre[maxn*10],nxt[maxn*10],rt,h[maxn],cnt,dfn[maxn],low[maxn],id;bool cur[maxn],vis[maxn];
long long ans[maxn];
void add(int x,int y)
{
	pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt,
	pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt;
}
void tarjan(int x)
{
	dfn[x]=low[x]=++id,size[x]=1;int sum=0,flag=0;
	for(rg int i=h[x];i;i=nxt[i])
	{
		if(!dfn[pre[i]])
		{
			tarjan(pre[i]),size[x]+=size[pre[i]],low[x]=min(low[pre[i]],low[x]);
			if(low[pre[i]]>=dfn[x])
			{
				flag++,sum+=size[pre[i]];
				ans[x]+=1ll*size[pre[i]]*(n-size[pre[i]]);
				if(x!=rt||flag>1)cur[x]=1;
			}
		}
		else low[x]=min(low[x],dfn[pre[i]]);
	}
	if(cur[x])ans[x]+=1ll*(n-sum-1)*(sum+1)+n-1;
	else ans[x]=2*n-2;
}
int main()
{
	read(n),read(m);
	for(rg int i=1,x,y;i<=m;i++)read(x),read(y),add(x,y);
	for(rg int i=1;i<=n;i++)if(!dfn[i])rt=i,tarjan(i);
	for(rg int i=1;i<=n;i++)printf("%lld
",ans[i]);
}
原文地址:https://www.cnblogs.com/lcxer/p/10390577.html