E. Number of Simple Paths(環基樹 + 思維)
阿新 • • 發佈:2020-11-25
Codeforces Round #686 (Div. 3)E. Number of Simple Paths
題意
給你n個點n條邊的圖,讓你求樹上的簡單路徑數。
簡單路徑:從a->b的方法,需要注意的是1->2>3,3->2->1算一種
思路
顯然建成後的圖是一棵樹多了一條邊,這種圖又叫環基樹。
從下圖開始分析該題:
我們假設這個環的每一個點都是一棵樹,我們建圖。
在每個以環上的點為根的樹上的任意兩個點只有\(C_n^2\)的取法
其他的任意兩個點間的取法都是有兩種路徑共計\(C_n^2 * 2\)。
我們先假設任意兩個點間都有兩種到達方法那麼,\(ans = C_n^2\)
然後我們再減去只有一種方法的路徑,即為所求。
#include<bits/stdc++.h> using namespace std; typedef long long LL; //#define int long long const int maxn = 2e5 + 10; int deg[maxn], bfs[maxn]; vector<int>edge[maxn]; int f[maxn], num[maxn]; void init(int n) { for (int i = 1; i <= n; ++i) { f[i] = i; num[i] = 1; } } int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); } bool Union(int x, int y) { int fx = find(x); int fy = find(y); if (fx == fy) return 0; if (num[fx] > num[fy]) swap(fx, fy); num[fy] += num[fx]; f[fx] = fy; return 1; } bool is_root(int x) { return f[x] == x ? 1 : 0; } void solve() { int n; cin >> n; init(n); for (int i = 1; i <= n; ++i) { deg[i] = 0; edge[i].clear(); } for (int i = 1; i <= n; ++i) { int u, v; cin >> u >> v; edge[u].push_back(v); edge[v].push_back(u); ++deg[u]; ++deg[v]; } int cnt = 0; for (int i = 1; i <= n; ++i) if (deg[i] == 1) { bfs[++cnt] = i; --deg[i]; } for (int i = 1; i <= cnt; ++i) { int u = bfs[i]; for (auto v : edge[u]) { --deg[v]; Union(u, v); if (deg[v] == 1) { bfs[++cnt] = v; } } } LL ans = n * (n - 1LL); for (int i = 1; i <= n; ++i) { if (is_root(i)) { ans -= num[i] * (num[i] - 1LL) / 2; } } cout << ans << endl; } signed main() { int T; cin >> T; while (T--) { solve(); } }