[洛谷P3469][POI2008]BLO-Blockade

时间:2022-12-21 00:55:12

题目大意:给你一张无向图,求出删去每个点后有多少个有序点对无法互相到达

题解:缩点,然后找割点$DP$,非割点的答案为$2n-2$(有序点对),割点的答案为它各个子联通块大小之积加上$2n-2$

卡点:

 

C++ Code:

#include <cstdio>
#define maxn 100010
#define maxm 500010
int head[maxn], cnt;
struct Edge {
	int to, nxt;
} e[maxm << 1];
inline void add(int a, int b) {
	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
}

inline int min(int a, int b) {return a < b ? a : b;}
int n, m;
int DFN[maxn], low[maxn], idx;
int sz[maxn];
long long ans[maxn];
void tarjan(int u, int fa = 0) {
	DFN[u] = low[u] = ++idx;
	int SZ = 0;
	sz[u] = 1;
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (v != fa) {
			if (!DFN[v]) {
				tarjan(v, u);
				low[u] = min(low[u], low[v]);
				if (low[v] >= DFN[u])  {
					ans[u] += static_cast<long long> (sz[v]) * SZ;
					SZ += sz[v];
				}
				sz[u] += sz[v];
			} else low[u] = min(low[u], DFN[v]);
		}
	}
	ans[u] += static_cast<long long> (n - SZ - 1) * SZ;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 0, a, b; i < m; i++) {
		scanf("%d%d", &a, &b);
		add(a, b);
		add(b, a);
	}
	tarjan(1);
	for (int i = 1; i <= n; i++) {
		printf("%lld\n", ans[i] + n - 1 << 1);
	}
	return 0;
}