• 题解 LOJ6669 【Nauuo and Binary Tree】


    题目链接

    Solution Nauuo and Binary Tree

    题目大意:有一棵 (n) 个节点的二叉树,根节点为 (1),你可以通过询问两个点之间简单路径的距离来还原这棵树,(nleq 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
    ",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("
    ");
    	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;
    }
    
  • 相关阅读:
    结对第一次作业-原型设计(文献摘要热词统计)
    第一次作业-准备篇
    Docker 安装 redis
    Docker 安装 MySQL8
    个人作业——软件工程实践总结作业
    团队作业第二次—项目选题报告
    结对第二次—文献摘要热词统计及进阶需求
    结对第一次—原型设计(文献摘要热词统计)
    第一次作业-准备篇
    个人作业——软件工程实践总结
  • 原文地址:https://www.cnblogs.com/colazcy/p/13873185.html
Copyright © 2020-2023  润新知