思路:去掉点
i
i
i后,其他点无论如何都无法到达它了,所以答案首先是
2
∗
(
n
−
1
)
2*(n-1)
2∗(n−1).
其次,考虑这个点去掉之后,是否会造成一个点无法到达其他点了呢?也就是出现了新的连通分量,我们发现满足这个性质的点只能是割点.
对于一个割点,删去后,可能会使得它们分别裂成若干个连通分量
假设裂成了
s
z
1
,
s
z
2..
s
z
i
假设裂成了sz1,sz2..sz_i
假设裂成了sz1,sz2..szi,原本都是连通的.删去之后,两个不同连通块间无法到达,而且对于割点本身也无法到达任何点.
2
∗
(
n
−
1
)
+
∑
s
z
i
∗
(
n
−
s
z
i
)
2*(n-1)+\sum sz_i*(n-sz_i)
2∗(n−1)+∑szi∗(n−szi)
问题转化为如何求这个
s
z
i
sz_i
szi,对于每一个割点,我们需要求出删掉它之后,形成若干个连通块的
s
z
sz
sz.
在
T
a
r
j
a
n
Tarjan
Tarjan算法执行过程中,
l
o
w
[
v
]
>
=
l
o
w
[
u
]
,
表明将会马上形成一个点双
,
此时我们统计这个子树的
s
z
,
就能得到其中一个连通块的大小
low[v]>=low[u],表明将会马上形成一个点双,此时我们统计这个子树的sz,就能得到其中一个连通块的大小
low[v]>=low[u],表明将会马上形成一个点双,此时我们统计这个子树的sz,就能得到其中一个连通块的大小
但是,还有一个连通块我们忘记计算了,就是该割点上边那些祖先形成的连通块.
首先,我们把儿子形成连通块的节点数目挨个求出来,记为
s
u
m
sum
sum,那么父亲块的大小就是
n
−
s
u
m
−
1
n-sum-1
n−sum−1,对应贡献是
(
n
−
s
u
m
−
1
)
∗
(
n
−
(
n
−
s
u
m
−
1
)
)
=
(
n
−
s
u
m
−
1
)
∗
(
s
u
m
+
1
)
(n-sum-1)*(n-(n-sum-1))=(n-sum-1)*(sum+1)
(n−sum−1)∗(n−(n−sum−1))=(n−sum−1)∗(sum+1),此外还有
i
i
i这个点不能到达剩余的
(
n
−
1
)
个点
,
再加上
n
−
1
,
为什么不用
∗
2
,
是因为之前
(n-1)个点,再加上n-1,为什么不用*2,是因为之前
(n−1)个点,再加上n−1,为什么不用∗2,是因为之前
s
z
i
∗
(
n
−
s
z
i
)
已经考虑过一个方向不能到达了
sz_i*(n-sz_i)已经考虑过一个方向不能到达了
szi∗(n−szi)已经考虑过一个方向不能到达了
/*
You held me down but I broke free,
I found the love inside of me.
Now I don't need a hero to survive
Cause I already saved my life.
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
int dfs_clock = 0,dfn[maxn],low[maxn],sz[maxn];
ll ans[maxn];bool is_cut[maxn];
int n;
void dfs(int u,int fa){
dfn[u] = low[u] = ++dfs_clock;
sz[u] = 1;
int child = 0;
ll sum = 0;
for(auto v : G[u]){
if(!dfn[v]){
child++;dfs(v,u);
sz[u] += sz[v];
low[u] = min(low[u],low[v]);
if(low[v]>=dfn[u]){
ans[u] += 1LL*sz[v] * (n-sz[v]);
sum += sz[v];
if(u!=1||child>1) is_cut[u] = true;
}
}
else if(v!=fa&&dfn[v]<dfn[u]) low[u] = min(low[u],dfn[v]);
}
if(!is_cut[u]) ans[u] = 2*(n-1);
else ans[u] += 1LL*(n-sum-1)*(sum+1)+(n-1);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int m;cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;cin>>u>>v;
G[u].pb(v);G[v].pb(u);
}
dfs(1,0);
for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
}