\(\mathcal{Description}\)

  Link (hard) & Link (easy).

  这是一道交互题。

  给定一棵 \(n\) 个结点的树,其中有两个是特殊结点。每次你可以提出形如 \(x~c_1~c_2~\cdots~c_x\) 的询问,交互器会回答在点集 \(\{c_x\}\) 中,到两个特殊结点距离之和最小的结点 \(p\) 和这个最小距离和 \(d\)(若有多个 \(d\),回答任意一个)。你需要猜出两个特殊结点的编号。

  \(n\le10^3\),\(T\le10\) 组数据,询问次数上限为 \(11\) 次。

\(\mathcal{Solution}\)

  第一次询问,显然问所有的 \(n\) 个点,就能得到特殊点 \(x,y\) 间的距离 \(d\) 和 \(x,y\) 路径上的一个结点 \(p\)。

  以 \(p\) 为根,\(x,y\) 显然在 \(p\) 的两棵子树内。接下来,以 \(p\) 为圆心“画圆”——询问所有到 \(p\) 的距离为某一定值 \(l\) 的点集,就能得到一个新的距离 \(d'\)。若 \(d'=d\),说明 \(x,y\) 离 \(p\) 较远的一个点到 \(p\) 的距离 \(\ge d'\),否则,就 \(<d'\),所以可以二分 \(l\),花 \(\mathcal O(\log n)\) 次询问找到离 \(p\) 较远的那个特殊点。

  最后,设较远点 \(x\) 到 \(p\) 的距离为 \(l\),把到 \(p\) 距离为 \(d-l\) 的所有点拿出来再问一次就得到另一个特殊点 \(y\) 了(注意排除掉在 \(p\) 到 \(x\) 路径上的点)。

  但是,最坏情况会有 \(1+\lceil\log_210^5\rceil+1=12\) 次询问,刚好多一次 qwq。

  不过二分找到是“较远点”,所以其到 \(p\) 的距离一定在 \([\lfloor\frac{d}2\rfloor,d]\) 之间,取这个区间作为二分上下界。其大小显然不超过 \(\frac{n}2\),所以刚好能节约一次二分的询问。

  复杂度 \(\mathcal O(Tn)\)。

\(\mathcal{Code}\)

/* Clearink */

#include <cstdio>
#include <vector>
#include <assert.h> inline int rint () {
int x = 0, f = 1; char s = getchar ();
for ( ; s < '0' || '9' < s; s = getchar () ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
return x * f;
} const int MAXN = 1000;
int n, ecnt, mxd, head[MAXN + 5], fa[MAXN + 5], dep[MAXN + 5];
std::vector<int> all, eqdis[MAXN + 5];
bool ban[MAXN + 5]; struct Edge { int to, nxt; } graph[MAXN * 2 + 5]; inline void link ( const int s, const int t ) {
graph[++ ecnt] = { t, head[s] };
head[s] = ecnt;
} inline void collect ( const int u, const int d ) {
eqdis[dep[u] = d].push_back ( u ), mxd = d < mxd ? mxd : d;
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( ( v = graph[i].to ) ^ fa[u] ) {
fa[v] = u, collect ( v, d + 1 );
}
}
} inline void inter ( const std::vector<int>& pts, int& p, int& dis ) {
if ( pts.empty () ) return void ( p = dis = 0 );
printf ( "? %d", ( int ) pts.size () );
for ( int u: pts ) printf ( " %d", u );
putchar ( '\n' ), fflush ( stdout );
assert ( ~( p = rint (), dis = rint () ) );
} inline void clear () {
ecnt = mxd = 0, all.clear (), eqdis[0].clear ();
for ( int i = 1; i <= n; ++ i ) {
head[i] = dep[i] = fa[i] = ban[i] = 0;
eqdis[i].clear ();
}
} int main () {
char rep[20];
for ( int T = rint (); T --; ) {
clear ();
n = rint ();
for ( int i = 1, u, v; i < n; ++ i ) {
all.push_back ( i );
u = rint (), v = rint ();
link ( u, v ), link ( v, u );
}
int p, dis;
all.push_back ( n ), inter ( all, p, dis );
collect ( p, 0 );
int l = dis + 1 >> 1, r = mxd < dis ? mxd : dis, S = 0;
while ( l < r ) {
int mid = l + r + 1 >> 1, curp, curd;
inter ( eqdis[mid], curp, curd );
if ( curd > dis ) r = mid - 1;
else S = curp, l = mid;
}
if ( !S ) inter ( eqdis[l], S, r );
int oth = dis - dep[S], Q, tmp;
for ( int u = S; u ^ p; u = fa[u] ) ban[u] = true;
for ( auto it ( eqdis[oth].begin () ); it != eqdis[oth].end (); ++ it ) {
if ( ban[*it] ) {
eqdis[oth].erase ( it );
break;
}
}
inter ( eqdis[oth], Q, tmp );
printf ( "! %d %d\n", S, Q ), fflush ( stdout );
scanf ( "%s", rep ), assert ( rep[0] == 'C' );
}
return 0;
}

\(\mathcal{Details}\)

  一眼出 \(12\) 次询问的方法然后卡了半天 qwq……养成卡二分上下界的习惯对常数有极大好处。(

Solution -「CF 1370F2」The Hidden Pair (Hard Version)的更多相关文章

  1. Solution -「CF 1342E」Placing Rooks

    \(\mathcal{Description}\)   Link.   在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...

  2. Solution -「CF 923F」Public Service

    \(\mathscr{Description}\)   Link.   给定两棵含 \(n\) 个结点的树 \(T_1=(V_1,E_1),T_2=(V_2,E_2)\),求一个双射 \(\varph ...

  3. Solution -「CF 1023F」Mobile Phone Network

    \(\mathcal{Description}\)   Link.   有一个 \(n\) 个结点的图,并给定 \(m_1\) 条无向带权黑边,\(m_2\) 条无向无权白边.你需要为每条白边指定边权 ...

  4. Solution -「CF 599E」Sandy and Nuts

    \(\mathcal{Description}\)   Link.   指定一棵大小为 \(n\),以 \(1\) 为根的有根树的 \(m\) 对邻接关系与 \(q\) 组 \(\text{LCA}\ ...

  5. Solution -「CF 757F」Team Rocket Rises Again

    \(\mathcal{Description}\)   link.   给定 \(n\) 个点 \(m\) 条边的无向图和一个源点 \(s\).要求删除一个不同与 \(s\) 的结点 \(u\),使得 ...

  6. Solution -「CF 802C」Heidi and Library (hard)

    \(\mathcal{Descriptoin}\)   Link.   你有一个容量为 \(k\) 的空书架,现在共有 \(n\) 个请求,每个请求给定一本书 \(a_i\).如果你的书架里没有这本书 ...

  7. Solution -「CF 793G」Oleg and Chess

    \(\mathcal{Description}\)   Link.   给一个 \(n\times n\) 的棋盘,其中 \(q\) 个互不重叠的子矩阵被禁止放棋.问最多能放多少个互不能攻击的车.   ...

  8. Solution -「CF 1119F」Niyaz and Small Degrees

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个结点的树,边有边权,对于每个整数 \(x\in[0,n)\),求出最少的删边代价使得任意结点度数不超过 ...

  9. Solution -「CF 1480G」Clusterization Counting

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 阶完全图,边权为 \(1\sim\frac{n(n-1)}2\) 的排列.称一种将点集划分为 \(k\) ...

随机推荐

  1. Go语言系列之日志库zap

    在许多Go语言项目中,我们需要一个好的日志记录器能够提供下面这些功能: 能够将事件记录到文件中,而不是应用程序控制台. 日志切割-能够根据文件大小.时间或间隔等来切割日志文件. 支持不同的日志级别.例 ...

  2. Linux下Julia安装

    1.找到官网,执行 wget https://julialang-s3.julialang.org/bin/linux/x64/1.4/julia-1.4.0-linux-x86_64.tar.gz ...

  3. 《剑指offer》面试题27. 二叉树的镜像

    问题描述 请完成一个函数,输入一个二叉树,该函数输出它的镜像. 例如输入:      4    /   \   2     7  / \   / \ 1   3 6   9 镜像输出:      4 ...

  4. 《剑指offer》面试题58 - II. 左旋转字符串

    问题描述 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部.请定义一个函数实现字符串左旋转操作的功能.比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两 ...

  5. 在Rainbond上使用Locust进行压力测试

    Locust简介 Locust 是一种易于使用.可编写脚本且可扩展的性能测试工具.并且有一个用户友好的 Web 界面,可以实时显示测试进度.甚至可以在测试运行时更改负载.它也可以在没有 UI 的情况下 ...

  6. Parallel.For实现

    static class MyParallel { //4.0及以上用Task, Task的背后的实现也是使用了线程池线程 //static List<Task> tasks = new ...

  7. 解决nRF Connect for PC无法连接网络的问题(非FQ)

    各位小伙伴是不是也遇到过国内不能正常使用nRF Connect的问题,现在教大家一个十分有效的办法. 1.找到nrf connect的脚本配置文件"apps.json",默认在&q ...

  8. [硬件]USB TYPE C引脚定义

  9. C++构造函数语义学(一)(基于C++对象模型)

    如果一个类没有自己的构造函数,编译器会在需要的时候为其合成一个出来,俗称:合成默认构造函数.但是请注意是在需要的时候,并不是所有情况. 请看下面代码: 1 #include<iostream&g ...

  10. 推荐一个github国内访问加速神器GitHub520

    一.介绍 对 GitHub 说"爱"太难了:访问慢.图片加载不出来. 注: 本项目还处于测试阶段,仅在本机测试通过,如有问题欢迎提 issues 本项目无需安装任何程序,通过修改本 ...