1. 程式人生 > 實用技巧 >題解 LOJ6669 【Nauuo and Binary Tree】

題解 LOJ6669 【Nauuo and Binary Tree】

題目連結

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;
}