CF1370F The Hidden Pair 题解

Codeforces F1
Codeforces F2
Luogu F1
Luogu F2

Description.

树上交互,有两个标记点。
每次你询问一个点集,每次返回这个点集中到两标记距离和最小的点和这个距离和。
F1 \(14\) F2 \(11\) 次内询问出两个标记点。

Solution.

首先,什么信息都没有的情况下肯定很困难。
我们先询问全集,以返回的最小点为根,这样两个标记点就在两棵子树内,同时知道了链长。
考虑 binary search,二分较大目标点的深度。
每次可以把这层所有点拿出来问。
判断 dis 是不是和链长相等来判断较深的那个点是不是在这个深度以下。
这样需要 \(1+\log n+1 \approx 12\) 次,可以通过 F1。

考虑较深那个点的值域,发现 \(\in[\frac {dis}2,dis]\),然后就节约了二分的一次。

Coding.

点击查看代码
//Coded by leapfrog on 2021.10.29 {{{
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=1005;int as[N],at,dis;vector<int>d[N];
struct edge{int to,nxt;}e[N<<1];int n,et,head[N],rx,fg[N];
inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;}
inline pair<int,int> ask()
{
	printf("? %d ",at);for(int i=1;i<=at;i++) printf("%d%c",as[i],i==at?'\n':' ');
	fflush(stdout);int u,v;read(u,v);return make_pair(u,v);
}
inline void answer(int x,int y)
{
	printf("! %d %d\n",x,y),fflush(stdout);char ch[10];
	scanf("%s",ch);if(*ch=='I') exit(0);
}
inline void dfs0(int x,int fa,int dep,int rt)
{
	d[dep].push_back(x),fg[x]=rt;
	for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa) dfs0(e[i].to,x,dep+1,rt);
}
inline char check(int w)
{
	if(d[w].empty()) return 0;else at=d[w].size();
	for(int i=1;i<=at;i++) as[i]=d[w][i-1];
	pair<int,int>q=ask();if(q.second==dis) return rx=q.first,1;else return 0;
}
inline void solve()
{
	read(n),et=0;for(int i=1;i<=n;i++) head[i]=fg[i]=0;
	for(int i=1,x,y;i<n;i++) read(x,y),adde(x,y),adde(y,x);
	at=n;for(int i=1;i<=n;i++) as[i]=i,d[i].clear();
	pair<int,int>q=ask();int rt=q.first;dis=q.second;
	int l=(dis+1)/2,r=dis+1,rs=r;d[1].push_back(rt);
	for(int i=head[rt];i;i=e[i].nxt) dfs0(e[i].to,rt,2,e[i].to);
	while(l<=r) {int md=(l+r)>>1;if(check(md)) rs=md,l=md+1;else r=md-1;}
	int ds=dis-rs+2;at=0;
	for(size_t i=0;i<d[ds].size();i++) if(fg[d[ds][i]]^fg[rx]) as[++at]=d[ds][i];
	q=ask(),answer(rx,q.first);
}
int main() {int Ca;for(read(Ca);Ca--;) solve();return 0;}
原文地址:https://www.cnblogs.com/pealfrog/p/15481890.html