K The Flee Plan of Groundhog——BFS
题意
有一棵树
A 在点 1,B 在点 2
A的移动速度是每秒走过一条边,B的移动速度是每秒走过两条边(也可以只走一条)
前 t 秒 A 在不断的走向 B,B 不动
之后 B 开始移动,开始追 A,A 开始逃离
求问 A 最晚被追到的时间
分析
首先 A 在 t 秒的时候所在的位置是固定的,因为树上任意两点间路径是唯一的。所以可以把 B 为根,用树上倍增的方式来快速找到 A 的第 t 个祖先,即 A 开始的位置。
接下来 A 和 B 会开始追击,考虑到达每一个点的情况,考虑 A 到达每个点所需要的时间和 B 到达每个点的时间,对于这个点,取这两个时间中的较小者,即为 A 和 B 第一次到达这个点的时间。然后从 A 出发寻找最大的两者到达时间相等的点
AC code
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 100; vector<int> g[N]; int anc[N][20]; bool visit[N]; void dfs(int u, int fa) { anc[u][0] = fa; for (int i = 1; i <= 19; i++) anc[u][i] = anc[anc[u][i - 1]][i - 1]; for (auto &v: g[u]) if (v != fa) dfs(v, u); } int kthFa(int u, int k) { int bit = 0; while (k) { if (k & 1) u = anc[u][bit]; k >>= 1; bit++; } return u; } int mouseTime[N], catTime[N]; void solve() { int n, t; cin >> n >> t; for (int i = 0; i < n - 1; ++i) { int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u); } dfs(n, 0); int kf = kthFa(1, t); if (kf == 0) kf = n; queue<pair<int, int>> q; memset(visit, false, sizeof(bool) * (n + 10)); q.push({kf, 0}); while (!q.empty()) { auto cur = q.front(); q.pop(); mouseTime[cur.first] = cur.second; visit[cur.first] = true; for (auto item : g[cur.first]) { if (visit[item]) continue; q.push({item, cur.second + 1}); } } memset(visit, false, sizeof(bool) * (n + 10)); q.push({n, 0}); while (!q.empty()) { auto cur = q.front(); q.pop(); catTime[cur.first] = cur.second; visit[cur.first] = true; for (auto item : g[cur.first]) { if (visit[item]) continue; q.push({item, cur.second + 1}); } } memset(visit, false, sizeof(bool) * (n + 10)); q.push({kf, 0}); int ans = 0; while (!q.empty()) { auto cur = q.front(); q.pop(); visit[cur.first] = true; ans = max(ans, max((catTime[cur.first] + 1) / 2, mouseTime[cur.first])); if ((catTime[cur.first] + 1) / 2 <= mouseTime[cur.first]) { continue; } for (auto item : g[cur.first]) { if (visit[item]) continue; q.push({item, 0}); } } cout << ans << endl; } signed main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); #ifdef ACM_LOCAL freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); signed localTestCount = 1, localReadPos = cin.tellg(); char localTryReadChar; do { if (localTestCount > 20) throw runtime_error("Check the stdin!!!"); auto startClockForDebug = clock(); solve(); auto endClockForDebug = clock(); cout << "Test " << localTestCount << " successful" << endl; cerr << "Test " << localTestCount++ << " Run Time: " << double(endClockForDebug - startClockForDebug) / CLOCKS_PER_SEC << "s" << endl; cout << "--------------------------------------------------" << endl; } while (localReadPos != cin.tellg() && cin >> localTryReadChar && localTryReadChar != '$' && cin.putback(localTryReadChar)); #else solve(); #endif return 0; }