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\n",ans[i]);
}