1 条题解

  • 0
    @ 2026-5-4 17:47:22

    没有看懂之前的题解那么多内容在讲什么,所以自己写一篇。

    设叶子节点的集合为 SS,询问集合为 TT

    • 如果根节点不是叶子节点,我们让 STS\in T。所有叶子的 LCA 一定是根节点,所以此时 TT 的 LCA 一定是根节点。所以如果答案是 YES,根节点就属于 TT。不难发现这是一个 0/10/1 函数,可以二分解决。

    • 如果根节点是叶子节点,那么如果 TT 中包含根节点,那么 TT 的 LCA 一点是根节点,答案一定是 YES。否则 TT 的 LCA 不可能是根节点,答案一定是 NO。看起来可以直接二分。但是会有一个问题,就是当你的 TT 中只剩一个节点的边界情况不好处理。但是题目保证了至少有三个叶子节点,所以拉个之前已经确定不是根节点的叶子过来一起问就解决了。

    实际上,这两种情况可以直接合并,按照度数排序后直接二分即可。具体实现可以看看代码。

    int main() {
      cin >> n;
    
      for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        d[u]++, d[v]++;
      }
    
      iota(a, a + n + 1, 0);
      sort(a, a + n + 1,
           [](int i, int j) { return d[i] < d[j]; });
    
      cout << endl;
      int l = 1, r = n;
    
      while (l < r) {
        int mid = (l + r) >> 1;
    
        if (mid == 1)
          cout << "? 2 " << a[1] << ' ' << a[3];
    
        else {
          cout << "? " << mid;
          for (int i = 1; i <= mid; i++) cout << ' ' << a[i];
        }
    
        cout << endl;
        string s;
        cin >> s;
    
        if (s == "YES")
          r = mid;
        else
          l = mid + 1;
      }
    
      cout << "! " << a[r] << endl;
      return 0;
    }
    
    • 1

    信息

    ID
    7095
    时间
    1000ms
    内存
    2048MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者