CodeForces - 1404B Tree Tag (树形dp求树的直径)
题目大意:
有一棵\(n\)个点的树,\(Alice\)和\(Bob\)起初分别在树上的节点\(a\),\(b\)。
他们轮流在树上移动一段距离不超过\(da\),\(db\)的路径。
两点间的路径长度为两点间树上简单路径的边数。
如果\(Alice\)能在无限次追及中追到\(Bob\),则\(Alice\)赢,否则\(Bob\)赢。
思路:
设树的直径为\(tree_d\)。
共有三种情况\(Alice\)能够获胜。
- \(dis(a, b) \leq da\),即\(Alice\)能够一步追到\(Bob\)。
- \(da \geq \frac{db}{2}\),即\(Alice\)能够步步逼近\(Bob\)。
- \(\frac{tree_d}{2} \leq da\),即Alice的移动范围大于等于树的半径,则Alice只需到达直径的中心即获胜。
我们只需通过树形\(DP\)在\(O(n)\)时间内求出树的直径,判断一下\(da\),\(db\),\(tree_d\)以及\(dis(a, b)\)之间的关系即可。
Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
vector<int> G[N];
int dp[2][N];
int dis[N];
int tree_d;
void dfs(int u, int pre) { //树形DP求树的直径
for (int v : G[u]) {
if (v == pre) continue;
dis[v] = dis[u] + 1;
dfs(v, u);
if (dp[0][v] + 1 > dp[0][u]) {
dp[1][u] = dp[0][u];
dp[0][u] = dp[0][v] + 1;
} else if (dp[0][v] + 1 > dp[1][u]) {
dp[1][u] = dp[0][v] + 1;
}
}
tree_d = max(dp[0][u] + dp[1][u], tree_d);
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T; cin >> T;
while (T--) {
int n, a, b, da, db; cin >> n >> a >> b >> da >> db;
//init
tree_d = 0;
for (int i = 0; i <= n; i++) {
dis[i] = dp[0][i] = dp[1][i] = 0; G[i].clear();
}
for (int i = 1; i < n; i++) {
int x, y; cin >> x >> y;
G[x].push_back(y); G[y].push_back(x);
}
dfs(a, 0);
if (dis[b] <= da) {
cout << "Alice" << endl; continue;
}
if (2 * da >= db) {
cout << "Alice" << endl; continue;
}
if (tree_d <= 2 * da) {
cout << "Alice" << endl; continue;
}
cout << "Bob" << endl;
}
return 0;
}