zoukankan      html  css  js  c++  java
  • 题解 CF1174F 【Ehab and the Big Finale】

    从这个题来的 LOJ #6669. Nauuo and Binary Tree

    题目链接

    Solution CF1174F Ehab and the Big Finale

    题目大意:给定一棵节点数不超过 (2 imes10^5) 的树,其中隐藏一个节点 (x)。你可以询问一个点 (u)(x) 的距离,或者询问点 (u)(x) 路径上的第二个点((u) 必须为 (x) 的父亲)。在不超过 (36) 次询问内找出 (x)

    树链剖分、交互


    分析:我们仍然考虑树链剖分(重链剖分)

    做法与LOJ那题类似,初始链为 (1) 号点所在的链,如果 (x) 不在链上,我们就找出链底和 (x)(LCA),询问 (LCA)(x) 路径上的第二个点,跳到那个点(一定是轻儿子)所在的链上。重链剖分保证了询问次数是(O(logn))

    (LCA) 的话我们得一次询问完成,不然是过不去的。我一开始同时询问 (x) 到链顶和链底的距离来找 (LCA) ,这样每次跳一条链会询问三次,十分危险。

    可以利用树上差分来完成,假设点 (u) 到根的距离为 (dis[u]),那么我们先问出 (dis[x]),链底 (t)(dis) 我们已知,那么我们就可以求出 (LCA)(dis)

    (d(t,x)=dis[t]+dis[x]-2 imes dis[LCA])

    这样每次跳一条链我们只需要问 (2) 次,可以通过

    #include <cstdio>
    #include <cctype>
    #include <vector>
    using namespace std;
    const int maxn = 2e5 + 100;
    inline int read(){
    	int x = 0;char c = getchar();
    	while(!isdigit(c))c = getchar();
    	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    	return x;
    }
    inline int query_dis(int u){
    	printf("d %d
    ",u);
    	fflush(stdout);
    	int res;
    	scanf("%d",&res);
    	return res;
    }
    inline int query_nxt(int u){
    	printf("s %d
    ",u);
    	fflush(stdout);
    	int res;
    	scanf("%d",&res);
    	return res;
    }
    vector<int> G[maxn],chain[maxn];
    inline void addedge(int u,int v){G[u].push_back(v);}
    int dfn[maxn],siz[maxn],top[maxn],son[maxn],dep[maxn],faz[maxn],dfs_tot;
    inline void dfs1(int u){
    	dfn[u] = ++dfs_tot;
    	siz[u] = 1;
    	for(int v : G[u]){
    		if(v == faz[u])continue;
    		faz[v] = u;
    		dep[v] = dep[u] + 1;
    		dfs1(v);
    		siz[u] += siz[v];
    		if(siz[v] > siz[son[u]])son[u] = v;
    	}
    }
    inline void dfs2(int u,int tp = 1){
    	top[u] = tp;
    	chain[tp].push_back(u);
    	if(son[u])dfs2(son[u],tp);
    	for(int v : G[u]){
    		if(v == faz[u] || v == son[u])continue;
    		dfs2(v,v);
    	}
    }
    int n;
    int main(){
    	n = read();
    	for(int u,v,i = 1;i < n;i++)
    		u = read(),v = read(),addedge(u,v),addedge(v,u);
    	dfs1(1);
    	dfs2(1);
    	int now = 1;
    	int dx = query_dis(1);
    	while(true){
    		int dis = query_dis(chain[top[now]].back());
    		if(dis == 0){
    			int ans = chain[top[now]].back();
    			printf("! %d
    ",ans);
    			fflush(stdout);
    			return 0;
    		}
    		int dl = (dep[chain[top[now]].back()] + dx - dis) >> 1;
    		int lca = chain[top[now]][dl - dep[chain[top[now]].front()]];
    		if(dep[chain[top[now]].back()] - dep[lca] == dis){
    			printf("! %d
    ",lca);
    			fflush(stdout);
    			return 0;
    		}
    		now = query_nxt(lca);
    	}
    	return 0;
    }
    
  • 相关阅读:
    request实现登录
    python之对象
    python基础之迭代与解析
    python基础之函数
    linux expect命令使用入门
    Python socket
    1
    蓝牙
    SQL查询语句
    iOS常用小知识纪录
  • 原文地址:https://www.cnblogs.com/colazcy/p/13875490.html
Copyright © 2011-2022 走看看