[loj 2587] 「APIO2018」鐵人兩項
阿新 • • 發佈:2019-01-06
「APIO2018」鐵人兩項
題目大意
給出一個 \(n\) 個點,\(m\) 條邊的無向圖,問存在多少個互異三元組 \((s, c, f)\) 滿足存在兩條分別從 \(s\) 到 \(c\) ,\(c\) 到 \(f\) ,且點不重複的路徑
資料範圍
\(n \le 100000, m \le 200000\)
時空限制
1000ms, 1024MB
分析
圓方樹模板題
考慮對於一對 \((s, f)\) ,所有可能的 \(c\) 就是它們路徑上點雙裡的點,而且不算 \(s\) ,\(f\) ,建出圓方樹,考慮路徑上一個點雙的貢獻是它的大小,而割點會重複統計,所以讓圓方樹上圓點貢獻為 \(-1\)
總結
最開始想的是列舉 \(c\) 算貢獻,所以發現不可做時要更換思路啊...
Code
#include <cstdio> #include <cstring> #include <iostream> #include <vector> using namespace std; inline char nc() { static char buf[100000], * l = buf, * r = buf; if (l == r) r = (l = buf) + fread(buf, 1, 100000, stdin); if (l == r) return EOF; return *l++; } template<class T> void read(T & x) { x = 0; int f = 1, ch = nc(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = nc(); } while (isdigit(ch)) { x = x * 10 - '0' + ch; ch = nc(); } x *= f; } typedef long long ll; const int maxn = 100000 + 5; const int maxm = 200000 + 5; const int maxe = maxm * 2; const int maxnode = maxn * 2; int n, m; struct edge { int to, nex; edge(int to = 0, int nex = 0) : to(to), nex(nex) {} } g[maxe]; int head[maxn]; int ecnt; vector<int> adj[maxnode]; inline void addedge(int u, int v) { g[ecnt] = edge(v, head[u]), head[u] = ecnt++; g[ecnt] = edge(u, head[v]), head[v] = ecnt++; } inline void adde(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); } int dfc, dfn[maxn], low[maxn]; int top, sta[maxn]; int bcnt; int bccsiz[maxn]; int val[maxnode]; int siz[maxnode]; void tarjan(int u, int fa) { low[u] = dfn[u] = ++dfc; sta[++top] = u; siz[u] = 1; for(int i = head[u]; ~ i; i = g[i].nex) { int v = g[i].to; if(v != fa) { if(!dfn[v]) { tarjan(v, u); low[u] = min(low[u], low[v]); if(low[v] >= dfn[u]) { bcnt++; adde(n + bcnt, u); bccsiz[bcnt] = 1; while(true) { int x = sta[top--]; adde(n + bcnt, x); bccsiz[bcnt]++; siz[bcnt + n] += siz[x]; if(x == v) break; } siz[u] += siz[bcnt + n]; val[bcnt + n] = bccsiz[bcnt]; } } else low[u] = min(low[u], dfn[v]); } } } int all; ll an; void dfs(int u, int fa) { ll re = (ll)(all - siz[u]) * siz[u] * 2; int t = int(u <= n); for(unsigned int i = 0; i < adj[u].size(); ++i) { int v = adj[u][i]; if(v != fa) { dfs(v, u); re += (ll)t * siz[v] * 2; t += siz[v]; } } an += re * val[u]; } void solve() { for(int i = 1; i <= n; ++i) { val[i] = -1; } for(int i = 1; i <= n; ++i) if(!dfn[i]) { tarjan(i, -1); all = siz[i], dfs(i, -1); } cout << an << endl; } int main() { // freopen("testdata.in", "r", stdin); read(n), read(m); memset(head, -1, sizeof(head)); for(int i = 1; i <= m; ++i) { int u, v; read(u), read(v); addedge(u, v); } solve(); return 0; }