题解:P10553 [ICPC2024 Xi'an I] Guess The Tree
BuQiuRu4587 · · 题解
场上差
赛时做法。
这种完全二叉树的问题考虑分治递归处理。
首先考虑在树上随一个点,查询所有点与它的
不难发现可以得到它的所有祖先,设祖先
不仅如此,我们还可以知道每一个节点在哪个祖先的子树当中,这样就比较好递归处理了。
唯一的问题是,考虑我们最开始随出来的点
注意到,假如我们最开始随出来的是
实现的时候可以稍微精细化一点,比如对于
貌似
#include<bits/stdc++.h>
using namespace std;
int ask(int x,int y){
cout<<"? "<<x<<' '<<y<<endl;
int ret;cin>>ret;
return ret;
}
int fa[1<<10],siz[1<<10];
bool vis[1<<10];
bool cmp(int x,int y){
return siz[x]>siz[y];
}
vector<int> nxt[1<<10];
int n;
void solve(vector<int> vec,int F){
if(vec.size()<=2){
for(int u:vec) fa[u]=F;
return ;
}
if(vec.size()==3){
int lca=ask(vec[0],vec[1]);
fa[lca]=F;
for(int u:vec){
if(u==lca) continue;
fa[u]=lca;
}return ;
}
int s=vec[0];
map<int,bool> ma;
for(int i=1;i<(int)vec.size();i++){
int lca=ask(s,vec[i]);
if(lca==s) s=vec[i];
fa[vec[i]]=lca;
siz[lca]++;
ma[lca]=1;
}
vector<int> l;
for(auto u:ma){
if(u.first==s) continue;
l.push_back(u.first);
}
sort(l.begin(),l.end(),cmp);
fa[l[0]]=F;
for(int i=1;i<(int)l.size();i++){
fa[l[i]]=l[i-1];
}fa[s]=l.back();
for(int u:l) vis[u]=1,nxt[u].clear();vis[s]=1,nxt[s].clear();
for(int u:vec){
if(vis[u]) continue;
nxt[fa[u]].push_back(u);
}
for(int u:l){
solve(nxt[u],u);
}solve(nxt[s],s);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n;n=(1<<n)-1;
vector<int> vec;
for(int i=1;i<=n;i++){
fa[i]=-1;
vec.push_back(i);
}
solve(vec,-1);
cout<<"! ";
for(int i=1;i<=n;i++){
cout<<fa[i]<<" ";
}
}