NC24217. [USACO 2019 Jan P]Exercise Route
描述
农场由N块草地组成(1≤N≤2⋅10^5),方便起见编号为1…N,由M条双向的小路连接(1≤M≤2⋅10^5)。作为一种遵循规律的生物,奶牛们倾向于使用其中特定的N−1条小路作为她们日常在草地之间移动的路线——她们管这些叫“常规的”小路。从每块草地出发都可以仅通过常规的小路到达所有其他草地。
为了使她的晨跑更加有趣,Bessie觉得她应该选择一条包含一些非常规的小路的路线。然而,使用常规的小路能够使她感到舒适,所以她不是很想在她的路线中使用过多非常规的小路。经过一些思考,她认为一条好的路线应当形成一个简单环(能够不经过任何草地超过一次的情况下回到起点),其中包含恰好两条非常规的小路。
请帮助Bessie计算她可以使用的好的路线的数量。两条路线被认为是相同的,如果它们包含的小路的集合相等。
输入描述
输入的第一行包含N和M。以下M行每行包含两个整数ai和bi,描述了一条小路的两端。其中前N−1条是常规的小路。
输出描述
输出Bessie可以选择的路线的总数。
示例1
输入:
5 8 1 2 1 3 1 4 1 5 2 3 3 4 4 5 5 2
输出:
4
C++ 解法, 执行用时: 335ms, 内存消耗: 22576K, 提交时间: 2022-04-06 10:40:33
// USACO 2019 Jan P. Exercise Route #include <bits/stdc++.h> const int NN = 2e5 + 4; using namespace std; using VI = vector<int>; VI G[NN]; int fa[NN][20], D[NN], Sum[NN], Sz[NN], HH; void dfs(int u, int f, int d) { fa[u][0] = f, D[u] = d; for (int i = 1; (1 << i) <= d; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for (int v : G[u]) if (v != f) dfs(v, u, d + 1); } int lca(int u, int v) { if (D[u] < D[v]) swap(u, v); for (int i = HH; i >= 0; i--) if ((1 << i) & (D[u] - D[v])) // D[fa[u][i]] >= D[v]) u = fa[u][i]; if (u == v) return u; for (int i = HH; i >= 0; i--) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i]; return fa[u][0]; } int topBelow(int u, int anc) { if (u == anc) return 0; for (int i = HH; i >= 0; i--) if (D[fa[u][i]] > D[anc]) u = fa[u][i]; return u; } void dfs2(int u, int f, int s) { Sz[u] = s; for (int v : G[u]) if (v != f) dfs2(v, u, s + Sum[v]); } int main() { ios::sync_with_stdio(false), cin.tie(0); int n, m; cin >> n >> m, HH = ceil(log2(n)) + 1; for (int i = 1, x, y; i <= n - 1; i++) cin >> x >> y, G[x].push_back(y), G[y].push_back(x); dfs(1, 0, 1); long long ans = 0; VI A(m + 1), B(m + 1); map<pair<int, int>, int> Q; for (int i = n; i <= m; i++) { cin >> A[i] >> B[i]; int d = lca(A[i], B[i]), ta = topBelow(A[i], d), tb = topBelow(B[i], d); if (ta) ans -= ++Sum[ta]; if (tb) ans -= ++Sum[tb]; if (ta && tb) { if (ta > tb) swap(ta, tb); ans -= Q[{ta, tb}]++; } } dfs2(1, 1, 0); for (int i = n; i <= m; i++) ans += Sz[A[i]] + Sz[B[i]] - 2 * Sz[lca(A[i], B[i])]; cout << ans << "\n"; return 0; }