洛谷P3469 [POI2008]BLO-Blockade
题目大意
给定一张无向连通图,求每个点被删除之后有多少个有序点对(x,y) (x!=y,1<=x,y<=n)满足x无法到达y;
思路
这道题首先考虑的便是和求割点相关;
对于每个割点,以下称当这个点被删除时,当前连通块分裂出的几个连通块为“被割集”,记第 i 个被割集的元素数量为 ci ;
对于每个节点,其造成的影响 brk[i]=(n−1)∗2+∑(n−1−ci)ci ;对于非割点,影响仅有前一项;
在判断割点的整个dfs过程中,记以节点 i 为根的dfs树元素数量为ctp[i] ,满足low[to] >= dfn[u]
的子节点显然有 cj=ctpto ,造成的影响是 (n−1−cj)cj ,即每个被割集和整个图的其他部分均被分离;
当然,对于每个割点,还有一个特殊的被割集,即为包含该割点的父节点的被割集,记为 c0 。有 c0=n−1−∑j=1cj ,影响量同上;
实际实现中,并不需要特判割点计算 c0 ,对于非割点,影响量为0;
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5 + 5; const int M = 1e8; vector<int> rod[N]; int dfn[N], dc = 1; int low[N]; int cut[N]; ll n; ll brk[N]; ll ctp[N]; void dfs(int u, int r) { low[u] = dfn[u] = dc++; cut[u] = (u == r) ? 0 : 1; brk[u] = (n - 1) * 2; ctp[u] = 1; ll tmp = 0, stp = 0; for (int j = 0; j < rod[u].size(); j++) { int to = rod[u][j]; if (!dfn[to]) { dfs(to, r); low[u] = min(low[u], low[to]); ctp[u] += ctp[to]; if (low[to] >= dfn[u]) cut[u]++, tmp += ctp[to] * (n - ctp[to] - 1), stp += ctp[to]; } else { low[u] = min(low[u], dfn[to]); } } brk[u] += tmp + (n - stp - 1) * stp; } int main() { int m, a, b; cin >> n >> m; for (int i = 1; i <= m; i++) { scanf("%d%d", &a, &b); rod[a].push_back(b); rod[b].push_back(a); } dfs(1, 1); for (int i = 1; i <= n; i++) { printf("%lld\n", brk[i]); } return 0; }
|
ED
\