CodeForces - 1404B Tree Tag (树形dp求树的直径)

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;
}
posted @ 2020-09-24 16:12  Nepenthe8  阅读(186)  评论(0编辑  收藏  举报