Description
给定一张无向图,求每个点被封锁之后有多少个有序点对 ((x,y)(x e y,1le x,yle n)) 满足 (x) 无法到达 (y)。
Hint
- (1le nle 10^5)
- (1le mle 5 imes 10^5)
Solution
对第 (i) 个点分类讨论——如果 (i):
-
是割点:
- Tarjan 算法是一个搜索树的 DFS,设 ( ext{size}_i) 为当前结点的第 (i) 个子树的大小(结点数),共有 (k) 个子树,那么删去这个割点的答案即为:
(left[sum_{i = 1}^k ext{size}_i imes (n - ext{size}_i - 1) ight] + ext{sum} imes (n - ext{sum} - 1) + 2(n - 1)) - 其中,( ext{sum} = sum_{i = 1}^k ext{size}_i),这些都可以在 Tarjan 算法中完成。
- Tarjan 算法是一个搜索树的 DFS,设 ( ext{size}_i) 为当前结点的第 (i) 个子树的大小(结点数),共有 (k) 个子树,那么删去这个割点的答案即为:
-
不是割点:
- 很显然,其他的结点之间的连通性并不会受此影响,所以只是所以的有关于这一个点的点对没了,答案为 (2(n - 1))。
复杂度 (O(n + m))
Code
/*
* Author : _Wallace_
* Source : https://www.cnblogs.com/-Wallace-/
* Problem : Luogu P3469 POI2008 Blockade
*/
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 1e6 + 5;
vector<int> G[N];
int n, m;
int timer = 0;
int dfn[N], low[N];
bool cut[N];
int size[N];
long long ans[N];
void Tarjan(int x) {
dfn[x] = low[x] = ++timer, size[x] = 1;
int ch = 0, sum = 0;
for (auto y : G[x]) {
if (!dfn[y]) {
Tarjan(y), size[x] += size[y];
low[x] = min(low[x], low[y]);
if (low[y] >= dfn[x]) {
ans[x] += size[y] * 1LL * (n - size[y] - 1);
sum += size[y], ++ch;
if (x != 1 || ch > 1) cut[x] = true;
}
}
low[x] = min(low[x], dfn[y]);
}
if (!cut[x]) ans[x] = (n - 1) * 2;
else ans[x] += (n - sum - 1) * 1LL * sum + (n - 1) * 2;
}
signed main() {
scanf("%d%d", &n, &m);
for (register int i = 1, u, v; i <= m; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
Tarjan(1);
for (register int i = 1; i <= n; i++)
printf("%lld
", ans[i]);
return 0;
}