[POI 2008] BLO
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1123
[算法]
首先,如果一个点不是割点,那么,去掉该点后不连通的有序点对就为 : 2 * (n - 1)
否则,去掉这个点后,这个图就被分为了 :
1. 这个点本身
2. 这个点在搜索树上的一些子树
3. 除1,2这两部分的节点
我们可以通过乘法原理算出答案,详见代码
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 100010 #define MAXM 500010 struct edge { int to,nxt; } e[MAXM << 1]; int i,n,m,x,y,timer,tot; int size[MAXN],dfn[MAXN],low[MAXN],head[MAXN]; long long ans[MAXN]; bool visited[MAXN],is_cut[MAXN]; inline void addedge(int u,int v) { tot++; e[tot] = (edge){v,head[u]}; head[u] = tot; } inline void tarjan(int u) { int i,v,cnt,sum; size[u] = 1; dfn[u] = low[u] = ++timer; visited[u] = true; cnt = sum = 0; for (i = head[u]; i; i = e[i].nxt) { v = e[i].to; if (!visited[v]) { tarjan(v); size[u] += size[v]; low[u] = min(low[u],low[v]); if (dfn[u] <= low[v]) { sum += size[v]; cnt++; ans[u] += 1ll * size[v] * (n - size[v]); low[u] = min(low[u],low[v]); if (u != 1 || cnt > 1) is_cut[u] = true; } } else low[u] = min(low[u],dfn[v]); } if (!is_cut[u]) ans[u] = 2 * (n - 1); else ans[u] += 1ll * (n - 1) + 1ll * (n - sum - 1) * (sum + 1); } int main() { scanf("%d%d",&n,&m); for (i = 1; i <= m; i++) { scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } tarjan(1); for (i = 1; i <= n; i++) printf("%lld\n",ans[i]); return 0; }