题意
传送门 P3469 [POI2008]BLO-Blockade
题解
求无向图中每个点上的边被删除后,有多少个不连通的有序点对 ( x , y ) (x,y) (x,y)。对于非割点的节点 x x x,删除与其相连的边后,图中其余各点依然连通,此时答案为 2 × ( n − 1 ) 2\times (n-1) 2×(n−1)。
若节点
x
x
x 是割点,设搜索树上有
t
t
t 个节点满足割点法则
d
f
n
[
x
]
≤
l
o
w
[
y
]
,
e
(
x
,
y
)
∈
E
dfn[x]\leq low[y],e(x,y)\in E
dfn[x]≤low[y],e(x,y)∈E ,那么删除边后图中至多出现
t
+
2
t+2
t+2 个连通块,即:节点
x
x
x;
t
t
t 个以满足割点法则的节点为根的子树的节点组成的连通块;可能有一个非上述节点组成的连通块。设
s
z
[
x
]
sz[x]
sz[x] 为以
x
x
x 为根的子树大小,以图中各节点为有序对的第一个节点,就可以不重复地进行统计,此时答案为
1
×
(
n
−
1
)
+
∑
i
=
1
t
[
s
z
[
y
i
]
×
(
n
−
s
z
[
y
i
]
)
]
+
(
n
−
∑
i
=
1
t
s
z
[
y
i
]
−
1
)
×
(
∑
i
=
1
t
s
z
[
y
i
]
+
1
)
1\times (n-1) + \sum\limits_{i=1}^{t}[sz[y_i]\times (n-sz[y_i])]+ (n-\sum\limits_{i=1}^{t}sz[y_i]-1)\times (\sum\limits_{i=1}^{t}sz[y_i]+1)
1×(n−1)+i=1∑t[sz[yi]×(n−sz[yi])]+(n−i=1∑tsz[yi]−1)×(i=1∑tsz[yi]+1)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100005, maxm = 500005;
int N, M, rt = 1, sz[maxn], dfn[maxn], low[maxn], clk;
int head[maxn], nxt[maxm << 1], to[maxm << 1], tot;
bool cut[maxn];
ll res[maxn];
void add(int x, int y) { to[++tot] = y, nxt[tot] = head[x], head[x] = tot; }
void tarjan(int x)
{
dfn[x] = low[x] = ++clk;
sz[x] = 1;
int cnt = 0, sum = 0;
for (int i = head[x]; i; i = nxt[i])
{
int y = to[i];
if (!dfn[y])
{
tarjan(y);
low[x] = min(low[x], low[y]);
sz[x] += sz[y];
if (dfn[x] <= low[y])
{
++cnt;
sum += sz[y];
res[x] += (ll)sz[y] * (N - sz[y]);
if (x != rt || cnt > 1)
cut[x] = 1;
}
}
else
low[x] = min(low[x], dfn[y]);
}
if (cut[x])
res[x] += (ll)(sum + 1) * (N - sum - 1) + N - 1;
else
res[x] = (N - 1) << 1;
}
int main()
{
scanf("%d%d", &N, &M);
for (int i = 1; i <= M; ++i)
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b), add(b, a);
}
tarjan(rt);
for (int i = 1; i <= N; ++i)
printf("%lld\n", res[i]);
return 0;
}