CodeForces

Tree Tag

题目大意:

有一棵(n)个点的树,(Alice)(Bob)起初分别在树上的节点(a)(b)

他们轮流在树上移动一段距离不超过(da)(db)的路径。

两点间的路径长度为两点间树上简单路径的边数。

如果(Alice)能在无限次追及中追到(Bob),则(Alice)赢,否则(Bob)赢。

思路:

设树的直径为(tree_d)

共有三种情况(Alice)能够获胜。

  1. (dis(a, b) leq da),即(Alice)能够一步追到(Bob)
  2. (da geq frac{db}{2}),即(Alice)能够步步逼近(Bob)
  3. (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;
}
原文地址:https://www.cnblogs.com/Nepenthe8/p/13724614.html