题目大意:
有一棵(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;
}