[POI2008]BLO-Blockade
阿新 • • 發佈:2021-08-10
題目大意
給定一張無向圖,求每個點被封鎖之後有多少個有序點對 \((x,y)(x!=y,1<=x,y<=n)\),滿足 \(x\) 無法到達 \(y\)。
解題思路
首先可以確定這題需要先求割點 這不是一看就知道嗎???
然後對於圖上一點 \(x\),進行分類討論:
-
若點 \(x\) 不為割點,則貢獻為 \(2(n-1)\),因為除了這個點,其他 \((n-1)\) 個點都不能到達這個點,而反過來又算一種方法。
-
若點 \(x\) 為割點,則會把原圖分成 \(2\) 個部分:
-
\(u\)。
-
\(a\) 個連通塊。
然後設這些連通塊的大小分別為 \(siz_1,siz_2,siz_3,...,siz_{a}\)
對於連通塊,此時又可以分成 \(2\) 個部分:
- 在 \(u\) 的子樹中的 \(a-1\) 個聯通塊,只需在每次遇到 \(low[v]>=dfn[u]\),說明從 \(v\) 和 \(v\) 的子樹出發,若不經過 \(u\),則無法到達比 \(u\) 的 \(dfn\) 更小的節點,我們把 \(u\) 刪掉時,\(v\) 和 \(v\) 的子樹就成為了一個連通塊。
- 除了 \(u\) 和 \(u\) 的子樹,其他的節點自成一個聯通塊(因為 \(u\) 是一個割點),只需在遇到 \(low[v]>=dfn[u]\) 時,用變數 \(sum\) 累加在 \(u\) 和 \(u\) 的子樹中的連通塊大小,那麼這一部分的貢獻為 \(sum \times (n-sum)\)。
此時,點 \(u\) 的貢獻為 \((n-1)\),注意不需要 \(\times 2\),因為反過來的方案已經在上面計算過了。
-
AC CODE
#include<bits/stdc++.h> #define _ 1000010 using namespace std; struct Fastio { template <typename T> inline Fastio operator>>(T &x) { x = 0; char c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); return *this; } inline Fastio &operator<<(const char c) { putchar(c); return *this; } inline Fastio &operator<<(const char *str) { int cur = 0; while (str[cur])putchar(str[cur++]); return *this; } template <typename T> inline Fastio &operator<<(T x) { if (x == 0) { putchar('0'); return *this; } if (x < 0) putchar('-'), x = -x; static int sta[45]; int top = 0; while (x) sta[++top] = x % 10, x /= 10; while (top) putchar(sta[top] + '0'), --top; return *this; } } io; int n, m, rt; int tot, head[_], to[_ << 1], nxt[_ << 1]; int cnt_node, dfn[_], low[_]; int siz[_]; bool cut[_]; long long ans[_]; void add(int u, int v) { to[++tot] = v; nxt[tot] = head[u]; head[u] = tot; } void tarjan(int u) { dfn[u] = low[u] = ++cnt_node; siz[u] = 1; int flag = 0; long long sum = 1; for(int i = head[u]; i; i = nxt[i]) { int v = to[i]; if(!dfn[v]) { tarjan(v); siz[u] += siz[v]; low[u] = min(low[u], low[v]); if(low[v] >= dfn[u]) { flag++; sum += siz[v]; ans[u] += (long long)siz[v] * (n - siz[v]); if(rt != u || flag > 1) cut[u] = 1; } } else low[u] = min(low[u], dfn[v]); } if(!cut[u]) ans[u] = (long long)2 * (n - 1); else ans[u] += (long long)(n - sum) * sum + (n - 1); } signed main() { io >> n >> m; for(int i = 1; i <= m; ++i) { int u, v; io >> u >> v; add(u, v); add(v, u); } tarjan(rt = 1); for(int i = 1; i <= n; ++i) printf("%lld\n", ans[i]); return 0; }