[eJOI2023] Tree Search 题解
看到
可以采用以下方法:一开始令
对于当前
上面的过程中可能遇到目标结点不在满足条件的子树里面,那么直接将整棵子树删去是正确的(实现中给该子树的根打上标记即可)。
询问次数
放代码(为原题交互格式,请自行修改为洛谷版本):
#include "stub.h"
#include<bits/stdc++.h>
using namespace std;
int solve(int n,vector<int> p){
vector<vector<int> > g(n);
for(int i=1;i<n;i++)
g[p[i-1]-1].emplace_back(i);
vector<bool> b(n);
vector<int> e(n);
int r=0;
function<void(int)> dfs=[&](int u){
for(int i:g[u])
if(!b[i])dfs(i),e[u]+=e[i];
}; // 计算子树大小
function<int(int)> f=[&](int u){
vector<int> s;
for(int i:g[u])
if(!b[i])s.emplace_back(i);
if(s.size()>1&&e[s[1]]>e[s[0]])swap(s[0],s[1]);
for(int i:s){
if(e[i]<<1<=e[r])return i; // 满足条件
if(int x=f(i);~x)return x; // 继续找儿子
}
return -1;
}; // 找满足条件的子树
while(1){
fill(e.begin(),e.end(),1);
if(dfs(r);e[r]==1)return r+1;
if(int x=f(r);ask(x+1))r=x; // 在该子树内
else b[x]=true; // 在另一棵子树里面
}
}