1. 程式人生 > 實用技巧 >題解 CF1404B 【Tree Tag】

題解 CF1404B 【Tree Tag】

CF1405D 題解

題目大意

給定你一棵樹, \(Alice\)\(Bob\) 初始在這棵樹上的節點 \(a\), \(b\)

他們可以在樹上輪流移動一段距離不超過 \(da\)\(db\) 的路徑。

路徑的定義是 \(2\) 點之間簡單路徑的邊數。

如果 \(Alice\) 追到了 \(Bob\) ,那麼則算 \(Alice\) 贏,否則算 \(Bob\) 贏。

題解

我們考慮一下,如果是一條鏈,那麼 \(Alice\) 一定會不停的把 \(Bob\) 往首尾比逼。

只有當 \(Bob\) 可以跨越 \(Alice\) 下一步所能覆蓋的範圍的時候他才可能逃出 \(Alcie\)

的魔爪

如這張圖

藍色的是 \(Alice\) ,紅色的是 \(Bob\) 只有 \(da > 2 * db\) 的時候他才可以逃出魔爪。

但是有另一種情況,就是如果 \(2 * db > len\) 那麼 \(Alice\) 可以每次都到達鏈上任意一點。

那麼我們搬回樹上。

我們只需要考慮 \(da\)\(2 * db\) 的關係。

然後最後考慮的鏈的長度,我們只要代入成樹的直徑即可。

程式碼

#include <iostream>
#include <string.h>
using namespace std;
const int maxn = 100010;
int T, n, a, RT, b, da, db, cnt, x, y, head[maxn];
struct node {
    int to, nxt, dep;
} e[maxn << 1];
void add(int x, int y) {
    e[++ cnt] = (node) {y, head[x], 0};
    head[x] = cnt;
}
void Dfs(int x, int fa) {
    e[x].dep = e[fa].dep + 1;
    if(e[x].dep > e[RT].dep) {
        RT = x;
    }
    for(int i = head[x]; ~i ; i = e[i].nxt) {
        int v = e[i].to;
        if(v != fa) {
            Dfs(v, x);
        }
    }
}
int main() {
    // freopen("a.in", "r", stdin);
    // freopen("a.out", "w", stdout);
    cin >> T;
    while(T --) {
        cin >> n >> a >> b >> da >> db;
        memset(head, -1, sizeof(head));
        for(int i = 1; i < n; ++ i) {
            cin >> x >> y;
            add(x, y), add(y, x);
        }
        if(db <= (da << 1)) {
            puts("Alice");
            continue;
        }
        RT = a;
        Dfs(a, 0);
        if(e[b].dep <= da + 1) {
            puts("Alice");
            continue;
        }
        Dfs(RT, 0);
        if(e[RT].dep - 1 <= (da << 1)) {
            puts("Alice");
            continue;
        }
        else {
            puts("Bob");
            continue;
        }
    }
    return 0;
}