题目:BZOJ1123
解析:
割点。
对于一个点
p
p
p,分两种情况:
1.
p
p
p不是割点,那么把与它关联的边去掉之后,整个图就分为
p
p
p与其余所有点。
1.
p
p
p是割点,那么把与它关联的边去掉之后,整个图会分为若干个连通块。我们应该求出这些连通块的大小,再两两相乘再相加,为了方便处理,我们将这些连通块分为:
1.节点
p
p
p本身。
2.分别由搜索树上以
p
p
p为根的子树中的节点构成。
3.剩余部分。
代码:
#include <bits/stdc++.h>
using namespace std;
const int Maxn=100005;
const int Maxm=500005;
int n,m,s,Index;
int first[Maxn],vis[Maxn],num[Maxn],low[Maxn],size[Maxn];
long long ans[Maxn];
struct shu{int to,next;}e[Maxm<<1];
inline int get_int()
{
int x=0,f=1;char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c=getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void print(long long x)
{
if(x<0) x=-x,putchar('-');
if(x>9) print(x/10);
putchar('0'+x%10);
}
inline void build(int x,int y){e[++s].next=first[x],first[x]=s,e[s].to=y;}
inline void tarjan(int p)
{
int flag=0,sum=0;
low[p]=num[p]=++Index,size[p]=1;
for(int u=first[p];u;u=e[u].next)
{
int to=e[u].to;
if(!num[to])
{
tarjan(to),low[p]=min(low[p],low[to]),size[p]+=size[to];
if(low[to]>=num[p])
{
flag++,ans[p]+=(long long)size[to]*(n-size[to]),sum+=size[to];
if(p!=1||flag>1) vis[p]=1;
}
}
else low[p]=min(low[p],num[to]);
}
if(vis[p]) ans[p]+=(long long)(n-sum-1)*(sum+1)+n-1;
else ans[p]=2*(n-1);
}
int main()
{
n=get_int(),m=get_int();
for(int i=1;i<=m;i++)
{
int x=get_int(),y=get_int();
if(x==y) continue;
build(x,y),build(y,x);
}
tarjan(1);
for(int i=1;i<=n;i++) print(ans[i]),putchar('\n');
return 0;
}