題意:給定一顆n個結點的樹,樹上有m個結點有隊伍,求存不存在一個點s,到所有m個隊伍所在結點的距離相等,如果存在輸出可能一個的s。
分析:假設存在s,那么可以改變樹的順序,使得s是所有隊伍結點的祖先,此時s的所有祖先都是滿足的s,令所有滿足條件的s中里隊伍結點最近的s為ms。dfs可以求得隊伍結點中的直徑,直徑端點為st,ed。如果直徑是奇數,肯定不存在,因為已知不存在與st,ed距離相等的點。如果直徑是偶數,令直徑的中點為c,因為假設s存在,所以st,ed的中點一定是所有點的中點,而且此時c一定是ms,此時驗證c是否滿足條件即可。dfs驗證c到所有隊伍結點的距離是否相等,如果滿足條件,輸出c。
需要注意的是,當只有一個隊伍節點時,st=ed,兩遍dfs找直徑時需要把直徑長度置為0,否則無法找到ed。
代碼:
#include <bits/stdc++.h> #define mp make_pair #define debug(x) cout << #x << ": " << x << endl #define pb push_back typedef long long LL; const int maxn = 3e5 + 10; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; using namespace std; int n, m, len, u, v, f[maxn], path[maxn], st, ed, dis[maxn], c; vector<int> g[maxn]; void dfs(int now, int pre,int steps) { if (f[now]) { if (steps >= len) { st = now; len = steps; } } for (int i = 0; i < g[now].size(); ++i) { int to = g[now][i]; if (to == pre) continue; dfs(to, now, steps + 1); } } void _dfs(int now, int pre, int steps) { if (f[now]) dis[now] = steps; for (int i = 0; i < g[now].size(); ++i) { int to = g[now][i]; if (to == pre) continue; _dfs(to, now, steps + 1); } } void __dfs(int now, int pre, int steps) { if (f[now]) { if (steps >= len) { ed = now; len = steps; } } for (int i = 0; i < g[now].size(); ++i) { int to = g[now][i]; if (to == pre) continue; path[to] = now; __dfs(to, now, steps + 1); } } int main() { ios::sync_with_stdio(0); cin.tie(0); cin >> n >> m; st = ed = len = 0; for (int i = 1; i < n; ++i) { cin >> u >> v; g[u].pb(v); g[v].pb(u); } for (int i = 0; i < m; ++i) { cin >> u; f[u] = 1; } dfs(1, 0, 0); len = 0; __dfs(st, 0, 0); if (len & 1) { cout << "NO\n"; } else { int temp = ed; int cnt = 0; while (cnt != len / 2) { temp = path[temp]; ++cnt; } c = temp; _dfs(c,0,0); int x = -1; for (int i = 1; i <= n; ++i) { if (f[i]) { if (x == -1) x = dis[i]; else if (dis[i] != x) { cout << "NO\n"; exit(0); } } } cout << "YES\n" << c; } }