当前位置: 首页 > java >正文

题解:CF2106G2 Baudelaire (hard version)

由 G1 可知,只要能确定根节点的位置,就能够用 n n n 次操作获得答案。因此,本题就需要在不超过 200 200 200 次的询问中获得根节点的位置。

设当前点为 u u u,与 u u u 相邻的点组成集合 S S S。若当前询问集合 Q Q Q 满足, Q ⊂ S Q \subset S QS,则可以进行操作:

  1. 1 1 1 操作询问 Q Q Q,获得答案 s x sx sx
  2. 进行 2 2 2 操作,翻转 u u u
  3. 再次用 1 1 1 操作询问 Q Q Q,获得答案 s y sy sy

可以发现,若 ∣ s x − s y ∣ = 2 × ∣ Q ∣ |sx - sy| = 2 \times |Q| sxsy=2×Q,则 Q Q Q 中不存在 u u u 的父亲节点。

利用这个性质,可以先找到以 u u u 为子树的重心 c c c,然后将 c c c 所有相邻的点加入集合中,通过二分法找到哪一个子结点与根距离最近。具体来说,分为以下情况:

  • c c c 已经不存在相邻点–此时 c c c 即为所求。
  • 询问 c c c 所有相邻的点且符合以上条件-- c c c 为所求。
  • 剩下的情况就进行二分操作。

综上所述,至多需要约 n + 3 × ⌈ log ⁡ ( n ) ⌉ n + 3 \times \lceil\log (n)\rceil n+3×log(n)⌉ 次询问之后就能找到根节点。最后进行一次 dfs 并询问即可求出答案。

#include <bits/stdc++.h>
#define init(x) memset (x,0,sizeof (x))
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define pii pair <int,int>
using namespace std;
const int MAX = 1e5 + 5;
const int MOD = 1e9 + 7;
inline int read ();
int t,n;
int main ()
{t = read ();while (t--){n = read ();int tot = 0,c = 0;vector <int> ans (n + 1),sz (n + 1),w (n + 1),vis (n + 1,0);vector <vector <int>> ve (n + 1);for (int i = 1;i < n;++i) {int u = read (),v = read ();ve[u].push_back (v);ve[v].push_back (u);}auto query1 = [&] (vector <int> p) -> int{printf ("? 1 %d ",p.size ());for (auto v : p) printf ("%d ",v);puts ("");fflush (stdout);return read ();};auto query2 = [&] (int x) -> void {printf ("? 2 %d\n",x);fflush (stdout);};auto dfs1 = [&] (auto self,int u,int fa) -> void{sz[u] = 1;for (auto v : ve[u]){if (v == fa || vis[v]) continue;self (self,v,u);sz[u] += sz[v];}};auto dfs2 = [&] (auto self,int u,int fa,int pre) -> void{ans[u] = query1 ({u}) - pre;for (auto v : ve[u]){if (v == fa) continue;self (self,v,u,pre + ans[u]);}};auto cen = [&] (auto self,int u,int fa) -> void{sz[u] = 1;w[u] = 0;for (auto v : ve[u]){if (v == fa || vis[v]) continue;self (self,v,u);sz[u] += sz[v];w[u] = max (w[u],sz[v]);}w[u] = max (w[u],tot - sz[u]);if (w[u] <= tot / 2) c = u;};auto ask = [&] (vector <int> p) -> pii{int sx = query1 (p);query2 (c);int sy = query1 (p);return {sx,sy};};auto solve = [&] (auto self,int u) -> int // 找 rt{dfs1 (dfs1,u,u);tot = sz[u];cen (cen,u,u);vis[c] = 1;vector <int> g;for (auto v : ve[c])if (!vis[v]) g.push_back (v);if (g.empty ()) return c;//已经找到 rtint l = 0,r = g.size () - 1,res = 0;auto [sx,sy] = ask (g);if (abs (sx - sy) == 2 * g.size ()) return c;//重心即为 rtwhile (l <= r){int mid = (l + r) >> 1;vector <int> tmp;for (int i = 0;i <= mid;++i) tmp.push_back (g[i]);auto [sx,sy] = ask (tmp);if (abs (sx - sy) == 2 * tmp.size ()) l = mid + 1;else res = mid,r = mid - 1;}return self (self,g[res]);};dfs2 (dfs2,solve (solve,1),0,0);printf ("! ");for (int i = 1;i <= n;++i) printf ("%d ",ans[i]);puts ("");fflush (stdout);}return 0;
}
inline int read ()
{int s = 0;int f = 1;char ch = getchar ();while ((ch < '0' || ch > '9') && ch != EOF){if (ch == '-') f = -1;ch = getchar ();}while (ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar ();}return s * f;
}
http://www.xdnf.cn/news/2047.html

相关文章:

  • html+servlet项目中的echart图表
  • 期刊论文发表,对重复率和AI率要求多少才合格?
  • 【MySQL数据库入门到精通-07 函数-字符串函数、数值函数、日期函数和流程函数】
  • 微差压传感器、呼吸传感器
  • C++开发未来发展与就业前景:从底层基石到未来引擎
  • 无限debugger实现原理
  • 皖维 大病救助办理手续说明
  • 分层设计数据仓库的架构和设计高效数据库系统的方法
  • 大模型应用开发之LLM入门
  • AI大模型学习十二:‌尝鲜ubuntu 25.04 桌面版私有化sealos cloud + devbox+minio对象存储测试和漫长修改之路
  • apt 源切到国内时出现证书验证不过问题
  • 异步请求池控制同一时间并发
  • [官方IP] AXI Memory Init IP
  • GAEA情感坐标背后的技术原理
  • HashMap的源码解析
  • Gradle安装与配置国内镜像源指南
  • Jira、PingCode、Redmine等18款缺陷管理工具对比评测
  • 《深入理解计算机系统》阅读笔记之第七章 链接
  • 软件工程-进度管理-PERT图Gantt图
  • vc++ 如何调用poco库
  • 力扣面试150题--环形链表和两数相加
  • 攻克光纤液位传感器电磁干扰两大难题
  • 飞机会员日
  • Transformer(Trainer)和参数调优实践
  • 【Linux内核设计与实现】第三章——进程管理04
  • java网络原理4
  • 配合图解 SEG-SAM: Semantic-Guided SAM for Unified Medical Image Segmentation
  • 三格电子——如何解决工业场景中以太网设备布线不方便的问题
  • 海外红人营销+用户反馈闭环:2025跨境电商品牌持续优化策略
  • 【前缀和计算和+哈希表查找次数】Leetcode 560. 和为 K 的子数组