题目大意:
标题说的很清楚了.
题目思路:
根据树的重心的性质:两颗子树合并,新树重心一定在两个子树重心的连线上.
所以合并子树的时候,让子树们的重心往祖先跳。直到跳到重心结束.
PS:判定重心: 2 * 最大子树sz <= sz[u]即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 3e5 + 5;
const int mod = 1e9 + 7;
int sz[maxn] , res[maxn] , f[maxn] , mx[maxn];
vi e[maxn];
void dfs (int u , int fa){
sz[u] = 1; res[u] = u;f[u] = fa;
for (auto & v : e[u]){
if (v == fa) continue;
dfs(v , u);
sz[u] += sz[v];
mx[u] = max(mx[u] , sz[v]);
}
for (auto & v : e[u]){
if (v == fa) continue;
int now = res[v];
// 爆跳
bool ok = false;
do{
int tmx = max(mx[now] , sz[u] - sz[now]);
if (2 * tmx <= sz[u]){
res[u] = now;
ok = true;
break;
}
now = f[now];
if (ok) break;
}while (now != u);
}
return ;
}
int main()
{
ios::sync_with_stdio(false);
int n , m; cin >> n >> m;
for (int i = 2 ; i <= n ; i++) {
int x; cin >> x;
e[x].pb(i);
}
dfs(1 , 0);
for (int i = 1 ; i <= m ; i++){
int x; cin >> x;
cout << res[x] << endl;
}
return 0;
}