1. 程式人生 > >[POI2008]BLO-Blockade

[POI2008]BLO-Blockade

滿足 div child cut ron new lin https struct

題目傳送門

題意:給定一張無向圖,求每個點被封鎖之後有多少個有序點對$(x,y)(x!=y,1<=x,y<=n)$滿足$x$無法到達$y$。

題目強調了所有村莊都相互可達。

首先會想到割頂,因為如果刪去割頂,就會導致圖的連通塊增加。反之不變。

不是割頂答案就應該是$(n-1)*2$。因為連通塊沒有增加意味著除去該點其他任意點對都可直接或間接可達,不可達的是該點與其他點之間來回的連接。

如果是割頂,實際上答案就是上面的基礎上加上各個連通塊之間的答案。

但如果刪去割頂再判斷復雜度變成$O(n^2)$會$TLE$。

於是我們在$Tarjan$的過程中順便求下。

如果刪去這個點有$n$個連通塊,每個的大小為$son_i$,那麽答案應該是$2\sum_{i=1}^n \sum_{j=i+1}^n son_i \times son_j$。

變形下也就是$son_i$要與所有$son_j,j=\{ 1,2,..,i-1\}$相乘。

所以我們每統計一個連通塊只要維護$son_i$和$\sum_{j=1}^{i-1}son_j$即可。

在$Tarjan$過程中,就是$dfs$其相連結點時,如果子結點及其後繼結點不能訪問到此結點的祖先結點則說明該結點底下是連通塊,應該統計。

最後會剩余該結點的祖先結點,它們會構成連通塊,大小為$n-\sum_{i=1}^n son_i - 1$。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5
#define re register 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i) 7 #define repd(i, a, b) for (re int i = a; i >= b; --i) 8 #define maxx(a, b) a = max(a, b); 9 #define minn(a, b) a = min(a, b); 10 #define LL long long 11 #define inf (1 << 30) 12 13 inline int read() {
14 int w = 0, f = 1; char c = getchar(); 15 while (!isdigit(c)) f = c == - ? -1 : f, c = getchar(); 16 while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ 0), c = getchar(); 17 return w * f; 18 } 19 20 const int maxn = 1e5 + 10, maxm = 5e5 + 10; 21 22 struct Edge { 23 int u, v, pre; 24 }; 25 26 struct Graph { 27 Edge edges[maxm << 1]; 28 int n, m; 29 int G[maxn]; 30 int dfs_clock, low[maxn], pre[maxn], iscut[maxn]; 31 LL sum[maxn], sc[maxn], ans[maxn]; 32 void init(int n) { 33 this->n = n; 34 m = 0; 35 memset(G, 0, sizeof(G)); 36 } 37 void Add(int u, int v) { 38 edges[++m] = (Edge){u, v, G[u]}; 39 G[u] = m; 40 } 41 // int tag[maxn], tot[maxn]; 42 void dfs(int u, int fa) { 43 low[u] = pre[u] = ++dfs_clock; 44 int child = 0; 45 for (register int i = G[u]; i; i = edges[i].pre) { 46 int v = edges[i].v; 47 if (!pre[v]) { 48 child++; 49 dfs(v, u); 50 if (low[v] >= pre[u]) { 51 ans[u] += sum[u] * sc[v]; 52 sum[u] += sc[v]; 53 } 54 sc[u] += sc[v]; 55 minn(low[u], low[v]); 56 if (low[v] >= pre[u]) iscut[u] = 1; 57 } else { 58 if (v != fa) 59 minn(low[u], pre[v]); 60 } 61 } 62 if (u == fa && child == 1) iscut[u] = 0; 63 sc[u]++; 64 } 65 void Tarjan() { 66 dfs_clock = 0; 67 rep(i, 1, n) 68 if (!pre[i]) 69 dfs(i, i); 70 rep(i, 1, n) 71 if (!iscut[i]) { 72 printf("%lld\n", (n-1LL) << 1); 73 } 74 else printf("%lld\n", (ans[i] + (n-sum[i]-1)*sum[i] + n-1) << 1); 75 } 76 } G; 77 78 int n, m; 79 80 int main() { 81 n = read(), m = read(); G.init(n); 82 rep(i, 1, m) { 83 int u = read(), v = read(); 84 G.Add(u, v); G.Add(v, u); 85 } 86 G.Tarjan(); 87 return 0; 88 }

[POI2008]BLO-Blockade