洛谷 P3469 BLO-Blockade

洛谷 P3469 BLO-Blockade

题意

给定一张无向图,求每个点被封锁之后有多少个有序点对 \((x,y)(x \ne y,1<=x,y<=n)\) 满足 \(x\) 无法到达 \(y\)

思路

使用 Tarjan 求出割点,有以下几种情况。

  1. 当前点不是割点,答案为 \(2\times (n-1)\),即该点与其他所有点不连通。
  2. 当前点是割点,答案由两部分组成,一是 dfs 树上儿子两两之间不连通,二是 dfs 树上子树内和子树外不连通,答案为 \(\sum_{v \in son_u} siz_{v} \times(n-siz_v)+(n-1)+(n-\sum_{v \in son_u}siz_v - 1)\times(\sum_{v \in son_u}siz_v + 1)\)

注意要加上本身与其他点不连通,\(son\) 只算删除当前点后与外部不连通的点,即 \(low_v \ge dfn_u\) 的点 \(v\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5, M = 5e5 + 5;
int tot, ver[M << 1], nxt[M << 1], head[N];
int n, m, low[N], dfn[N], siz[N], cnt;
ll ans[N]; bool g[N];
void add(int x, int y) {
	ver[++ tot] = y;
	nxt[tot] = head[x];
	head[x] = tot;
}
void tarjan(int x, int fa) {
	low[x] = dfn[x] = ++ cnt, siz[x] = 1;
	int s = 0, sum = 0;
	for (int i = head[x], y; i; i = nxt[i]) {
		y = ver[i];
		if (!dfn[y]) {
			tarjan(y, x);
			siz[x] += siz[y];
			if (low[y] >= dfn[x] && fa) g[x] = 1;
			if (low[y] >= dfn[x] || !fa) 
				ans[x] += 1ll * siz[y] * (n - siz[y]), sum += siz[y];
			low[x] = min(low[x], low[y]), s ++;
		} else if (y != fa) 
			low[x] = min(low[x], dfn[y]);
	}
	if (!fa && s >= 2) g[x] = 1;
	if (!g[x]) ans[x] = 2ll * (n - 1);
	else ans[x] += 1ll * n - 1ll + 1ll * (sum + 1) * (n - sum - 1);
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1, u, v; i <= m; i ++) {
		scanf("%d%d", &u, &v);
		add(u, v), add(v, u);
	}
	tarjan(1, 0);
	cerr << "g: ";
	for (int i = 1; i <= n; i ++) 
		if (g[i]) cerr << i << ' ';
	cerr << '\n';
	for (int i = 1; i <= n; i ++) 
		printf("%lld\n", ans[i]);
	return 0;
}
posted @ 2024-09-05 08:54  maniubi  阅读(5)  评论(0编辑  收藏  举报