題解 LOJ6669 【Nauuo and Binary Tree】
阿新 • • 發佈:2020-10-25
Solution Nauuo and Binary Tree
題目大意:有一棵 \(n\) 個節點的二叉樹,根節點為 \(1\),你可以通過詢問兩個點之間簡單路徑的距離來還原這棵樹,\(n\leq 3000\),詢問次數上限 \(30000\)
樹剖,互動
分析:首先詢問出所有點的深度,一層一層擴充套件。
加入一個點後就暴力樹剖一次,從 \(1\) 號點開始,每次詢問當前點和重鏈底的距離,求出 \(LCA\) 的深度,如果沒有找到父親,就跳到 \(LCA\) 的輕兒子繼續找。
#include <cstdio> #include <vector> using namespace std; const int maxn = 3333; int faz[maxn],dfn[maxn],top[maxn],siz[maxn],son[maxn],dep[maxn],dfs_tot,n; vector<int> G[maxn],vec[maxn],chain[maxn]; inline void addedge(int u,int v){ G[u].push_back(v); faz[v] = u; } inline void dfs1(int u){ dfn[u] = ++dfs_tot; siz[u] = 1; son[u] = 0; for(int v : G[u]){ if(v == faz[u])continue; dep[v] = dep[u] + 1; faz[v] = u; dfs1(v); siz[u] += siz[v]; if(siz[v] > siz[son[u]])son[u] = v; } } inline void dfs2(int u,int tp){ chain[tp].push_back(u); top[u] = tp; if(son[u])dfs2(son[u],tp); for(int v : G[u]){ if(v == faz[u] || v == son[u])continue; dfs2(v,v); } } inline void build(){ dfs_tot = 0; for(int i = 1;i <= n;i++)chain[i].clear(); dfs1(1); dfs2(1,1); } inline int query(int u,int v){ printf("? %d %d\n",u,v); fflush(stdout); int res = 0; scanf("%d",&res); return res; } inline void out(){ printf("! "); for(int i = 2;i <= n;i++)printf("%d ",faz[i]); printf("\n"); fflush(stdout); } int main(){ dep[1] = 1; scanf("%d",&n); vec[1].push_back(1); for(int i = 2;i <= n;i++) vec[query(1,i) + 1].push_back(i); for(int x : vec[2]) addedge(1,x); build(); for(int i = 3;!vec[i].empty();i++) for(int x : vec[i]){ int now = 1; while(true){ int dis = query(chain[top[now]].back(),x); if(dis == 1){ addedge(chain[top[now]].back(),x); build(); break; } int dl = (dep[chain[top[now]].back()] + i - dis) >> 1; int lca = chain[top[now]][dl - dep[chain[top[now]].front()]]; if(G[lca].size() < 2){ addedge(lca,x); build(); break; } for(int v : G[lca]) if(v != son[lca]){ now = v; break; } } } out(); return 0; }