【Codeforces Round #668 (Div. 2) D】Tree Tag
阿新 • • 發佈:2020-09-08
題目連結
翻譯
給你一棵樹,一個人(\(Alice\))在 \(a\) 處,一個人(\(Bob\))在 \(b\) 處,其中 \(a\) 每次可以移動到距離(經過的邊的個數)為 \(da\) 以內的任意一個點上,\(b\) 每次可以移動到距離為 \(db\) 以內的任意一個點上。
在 \(a\) 上的人 \(Alice\) 先移動,問 \(A\) 能否在有限次的移動過後和 \(Bob\) 在同一個節點上,如果能夠做到, 那麼 \(A\) 贏,否則 \(B\) 贏。\(A\) 和 \(B\) 都會採取有利於自己的最佳策略。
問你最後誰會贏。
題解
我們分成 \(4\) 類情況討論:
- \(dis(a,b)\le da\)
- \(2\times da\ge diameter(T)\), 其中 \(diameter(T)\) 表示樹的直徑。這種情況下, 只要 \(Alice\) 走到樹的直徑的中點上,那麼下一次輪到 \(Alice\) 走的時候,她就可以走到樹上的任意一個位置了,\(Bob\)也就無處藏身了,因此 \(Alice\) 贏。
- \(db > 2\times da\), 因為已經排除了第一種情況,所以我們可以保證 \(Bob\) 能至少移動那麼一次。我們可以採取這樣的策略: 在 \(Alice\)
\(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\) - \(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;
}