洛谷P3469[POI2008]BLO-Blockade
阿新 • • 發佈:2019-04-29
聯通塊 signed 乘法 ++ pac problem scan n-1 ans ,得到的是無序點對的個數。
題目
割點模板題。
可以將圖中的所有點分成兩部分,一部分是去掉之後不影響圖的連通性的點,一部分是去掉之後影響連通性的點,稱其為割點。
然後分兩種情況討論,如果該點不是割點,則最終結果直接加上2*(n-1)。如果是的話,就求子樹的每塊連通塊大小。
一個點的子樹可以分成兩類:存在返祖邊或不存在。
對於前者,割掉該點並不影響連通性,所以和祖先算作一個聯通塊;
對於後者,割掉該點將使得其變為獨立的聯通塊,所以在搜索時順便計算\(size\)。
於是可以方便地算出後者的\(size\)之和sum,而前者總大小即為\(n-sum-1\)。
在搜索時一邊累加\(sum\),一邊累加答案,最後加上\(n-1\)
然後乘法原理即可。
#include <iostream> #include <stdio.h> #include <vector> #include <algorithm> #include <cstring> #include <cmath> #define int long long using namespace std; struct edg { int to, len, nex; }e[1000100]; int lin[300100], dfn[300100], low[300100], siz[301000], cut[300100], tot, cnt, n, m; vector <int> s[300010]; inline void add(int f, int t) { e[++cnt].to = t; e[cnt].nex = lin[f]; lin[f] = cnt; } void Tarjan(int fa, int u) { dfn[u] = low[u] = ++tot; int temp; siz[u]++; temp = 1; for (int i = lin[u]; i; i = e[i].nex) { int to = e[i].to; if (to == fa) continue; if (!dfn[to]) { Tarjan(u, to); siz[u] += siz[to]; low[u] = min(low[u], low[to]); if (low[to] >= dfn[u]) { temp += siz[to]; s[u].push_back(siz[to]); cut[u] = 1; } } else low[u] = min(low[u], low[to]); }//求割點 s[u].push_back (n - temp); } signed main() { scanf("%lld%lld", &n, &m); for (int i = 1; i <= n; i++) s[i].reserve(5); for (int i = 1; i <= m; i++) { int a, b; scanf("%lld%lld", &a, &b); add(a, b); add(b, a); } Tarjan(0, 1);// for (int i = 1; i <= n; i++) { int ans = 2 * (n - 1);// if (s[i].size() >= 2)//如果他是割點且割了之後會分成兩塊那就 for (int j = 0; j < (int) s[i].size(); j++) for (int k = j + 1; k < (int) s[i].size(); k++) ans += 2 * s[i][j] * s[i][k];//無向圖,要乘2 printf("%lld\n", ans); } }
洛谷P3469[POI2008]BLO-Blockade