ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【luogu CF1370F】The Hidden Pair(构造)

2022-03-27 09:32:35  阅读:183  来源: 互联网

标签:一个点 int luogu 路径 深度 Pair Hidden now ds


The Hidden Pair

题目链接:luogu CF1370F1 / luogu CF1370F2

题目大意

给你一棵树,然后你要猜两个特殊点。
每次你可以询问一个点集,会告诉你这个点集中到两个特殊点距离之和最近的点以及这个距离和。
然后要你在至多 \(11\) 次操作猜出这两个点。
\(n\leq 1000\)

思路

首先看到这个操作次数跟 \(n\) 的关系不难猜到会用 \(\log\) 次左右。
然后你不难想到一开始要选全图问一次,求出这两个特殊点之间的路径长度 \(d\)。

那第一次给的点有什么用呢?你会发现它是两个特殊点之间的路径上的一个点。
然后我们进而能发现如果一个点在这个路径上,那它到这两个点的路径长度就是这两个点之间的长度,否则就会要大于它。

然后我们考虑能不能求出其中的一个点。(因为你找到之后把距离它为 \(d\) 的点都询问一次,得到的肯定是另一个点,毕竟别的点必定不在路径上)
考虑一个神奇的方法就是二分。

你考虑把你第一次给的点当做根,然后去找那个深度较大的点。
那你会发现你如果二分一个深度,每次询问把这个深度的所有点都拿去询问,那如果得到的点的距离和是 \(d\),也就是说这个深度还有点在两个点的路径中,否则就没了。
那我们找到最大的深度的时候,这个点必定是路径其中的一个端点。

然后我们看看操作次数:
一开始一次,中间 \(\log\) 次,最后一次:\(1+10+1=12\) 刚好超了一个。
(这个时候简单版已经能过了)

那怎么优化呢?其实有个小小的性质,就是在二分的时候,你下界 \(l\) 不一定要从 \(0\) 开始。
毕竟你路径长度为 \(d\),你还要找深度大的点,那它至少的深度会在 \(\left\lceil\frac{d}{2}\right\rceil\),那把 \(l\) 一开始弄成这个,就刚好少了一次操作!

代码

#include<cstdio>
#include<vector>
#define clean() fflush(stdout)

using namespace std;

const int N = 1000 + 10;
int TT, n, x, y, d, deg[N], S, T;
vector <int> G[N], ds[N];
char s[11];

void dfs(int now, int father) {
	ds[deg[now]].push_back(now);
	for (int i = 0; i < G[now].size(); i++) {
		int x = G[now][i]; if (x == father) continue;
		deg[x] = deg[now] + 1; dfs(x, now);
	}
}

bool check(int x) {
	if (!ds[x].size()) return 0;
	printf("? %d", ds[x].size()); for (int i = 0; i < ds[x].size(); i++) printf(" %d", ds[x][i]); printf("\n"); clean();
	int rx, ry;
	scanf("%d %d", &rx, &ry);
	if (ry == d) {S = rx; return 1;}
	return 0;
}

int main() {
	scanf("%d", &TT);
	while (TT--) {
		scanf("%d", &n);
		for (int i = 1; i < n; i++) {
			scanf("%d %d", &x, &y); G[x].push_back(y); G[y].push_back(x);
		}
		
		printf("? %d", n); for (int i = 1; i <= n; i++) printf(" %d", i); printf("\n"); clean();
		scanf("%d %d", &x, &d);
		
		for (int i = 1; i <= n; i++) ds[i].clear();
		deg[x] = 0; dfs(x, 0);
		
		int l = (d + 1) / 2, r = d;
		while (l <= r) {
			int mid = (l + r) >> 1;
			if (check(mid)) l = mid + 1;
				else r = mid - 1;
		}
		
		for (int i = 1; i <= n; i++) ds[i].clear();
		deg[S] = 0; dfs(S, 0);
		printf("? %d", ds[d].size()); for (int i = 0; i < ds[d].size(); i++) printf(" %d", ds[d][i]); printf("\n"); clean();
		int tmp; scanf("%d %d", &T, &tmp);
		
		printf("! %d %d\n", S, T); clean();
		scanf("%s", s + 1); if (s[1] == 'I') return 0;
		
		for (int i = 1; i <= n; i++) G[i].clear();
	}
	
	return 0;
}

标签:一个点,int,luogu,路径,深度,Pair,Hidden,now,ds
来源: https://www.cnblogs.com/Sakura-TJH/p/luogu_CF1370F.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有