1. 程式人生 > 實用技巧 >【Codeforces Round #668 (Div. 2) D】Tree Tag

【Codeforces Round #668 (Div. 2) D】Tree Tag

題目連結

點我呀

翻譯

給你一棵樹,一個人(\(Alice\))在 \(a\) 處,一個人(\(Bob\))在 \(b\) 處,其中 \(a\) 每次可以移動到距離(經過的邊的個數)為 \(da\) 以內的任意一個點上,\(b\) 每次可以移動到距離為 \(db\) 以內的任意一個點上。

\(a\) 上的人 \(Alice\) 先移動,問 \(A\) 能否在有限次的移動過後和 \(Bob\) 在同一個節點上,如果能夠做到, 那麼 \(A\) 贏,否則 \(B\) 贏。\(A\)\(B\) 都會採取有利於自己的最佳策略。

問你最後誰會贏。

題解

我們分成 \(4\) 類情況討論:

  • \(dis(a,b)\le da\)
    , 那麼顯然 \(Alice\) 只需走一次,就能直接抓到 \(Bob\), 因此 \(Alice\) 贏。
  • \(2\times da\ge diameter(T)\), 其中 \(diameter(T)\) 表示樹的直徑。這種情況下, 只要 \(Alice\) 走到樹的直徑的中點上,那麼下一次輪到 \(Alice\) 走的時候,她就可以走到樹上的任意一個位置了,\(Bob\)也就無處藏身了,因此 \(Alice\) 贏。
  • \(db > 2\times da\), 因為已經排除了第一種情況,所以我們可以保證 \(Bob\) 能至少移動那麼一次。我們可以採取這樣的策略: 在 \(Alice\)
    沒有到達 \(Bob\)\(da\) 範圍以內,都按兵不動。一旦到了這個範圍內,那麼
    \(Bob\)\(Alice\) 的距離 \(d(a,b)\le da\),那麼我們馬上讓 \(Bob\) 走到一個和 \(Alice\) 距離為 \(da+1\) 的點 \(v\) 處, 因為 \(d(b,a)\le da\), 那麼 \(d(b,a)+d(a,v)\le da + da +1\), 即 \(d(b,v)\le 2\times da+1\), 而 \(db> 2\times da\),
    所以 \(Bob\) 是肯定能一次移動到這麼一個點 \(v\) 的。那麼 \(Bob\)
    也就每次都能在被抓的邊緣瘋狂試探了:), 因此 \(Bob\) 贏。這裡保證存在這麼一個點 \(v\) 的前提條件就是我們已經排除了第二種情況,不會出現所有的點 \(Alice\) 都能在一步之內走到。
  • \(db \le 2\times da\), 這種情況,我們可以把 \(Alice\) 所在的點 \(a\) 看做是樹的根節點,\(b\) 是在 \(a\) 的某個子樹中的 (距離根節點 \(v\) 的距離大於 \(da\) ,而且會發現,因為 \(db \le 2\times da\), 所以 \(a\) 永遠無法跳出它所在的子樹到達另外一棵子樹中去 (跳過去了也只會被抓到)。
    所以,我們只要每次讓 \(Alice\)\(b\) 所在的子樹下走一個節點 (這個時候 \(d(a,b)\) 最壞也只是變成 \(2\times da\), 那麼 \(b\) 依靠最大為 \(2\times da\)\(db\) 還是跳不出對應的子樹),然後一步一步逼近 \(b\) 就可以了,所以這種情況仍然是 \(Alice\) 贏。

求出 \(a\)\(b\) 的距離和 \(da\) 判斷一下,然後求出樹的直徑, 和 \(2\times da\) 比較一下, 最後用 \(2 \times da\) 再和 \(db\) 比較一下就可以了。

程式碼

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5;

int n,a,b,da,db,d1,d2,nextX;
vector<int> g[N + 10];

void dfs1(int x,int fa,int mydis){
    if (x == b){
        d1 = mydis;
        return;
    }
    int len = g[x].size();
    for (int i = 0;i < len; i++){
        int y = g[x][i];
        if (y == fa){
            continue;
        }
        dfs1(y,x,mydis + 1);
    }
}

void dfs2(int x,int fa,int mydis){
    if (mydis > d2){
        nextX = x;
        d2 = mydis;
    }
    int len = g[x].size();
    for (int i = 0;i < len; i++){
        int y = g[x][i];
        if (y == fa){
            continue;
        }
        dfs2(y,x,mydis+1);
    }
}

int main(){
    #ifdef LOCAL_DEFINE
        freopen("E://9.AlgorithmCompetition//Visitor.txt","r",stdin);
    #endif
    ios::sync_with_stdio(0),cin.tie(0);
    int T;
    cin >> T;
    while (T--){
        for (int i = 1;i <= n; i++){
            g[i].clear();
        }
        cin >> n >> a >> b >> da >> db;
        for (int i = 1;i < n; i++){
            int x, y;
            cin >> x >> y;
            g[x].push_back(y);
            g[y].push_back(x);
        }
        dfs1(a, -1, 0);
        if (da >= d1){
            cout << "Alice" << endl;
            continue;
        }
        d2 = 0;nextX = 1;
        dfs2(a,-1,0);
        d2 = 0;
        dfs2(nextX,-1,0);
        if (2*da >= d2){
            cout << "Alice" << endl;
            continue;
        }
        if (db > da*2){
            cout << "Bob" << endl;
        }else{
            cout << "Alice" << endl;
        }
    }
    return 0;
}