CF1592Ddfs序+二分

Posted hesorchen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1592Ddfs序+二分相关的知识,希望对你有一定的参考价值。

题目

D. Hemose in ICPC ?

交互题。

给出一棵树,点数<=1000,边权未知。你每次可以询问一个点集,会返回这些点集两两路径边权gcd的最大值。请你用至多12次询问确定两个点,使得他们之间的路径边权gcd即是最大值。

求解思路

这个点集的最大值,等价于路径上权值最大的一条边。也就是我们要找到最大边权的边。

2 12 > 1000 2^{12}>1000 212>1000。只需每次都排除掉半棵树,我们就可以以 O ( l o g n ) O(logn) O(logn)的时间复杂度找到答案。

可以用dfs序对边标号,这样所有边就是连续的。每次询问一半的边,排除掉一半。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e3 + 5;
vector<int> mp[N];
vector<pair<int, int>> dfn;

void dfs(int u, int fa)
{
    for (auto v : mp[u])
    {
        if (v == fa)
            continue;
        dfn.emplace_back(make_pair(u, v));
        dfs(v, u);
    }
}
int ask(int l, int r)
{
    set<int> st;
    for (int i = l - 1; i <= r - 1; i++)
        st.insert(dfn[i].first), st.insert(dfn[i].second);
    cout << "? " << st.size() << ' ';
    for (auto it : st)
        cout << it << ' ';
    cout << endl;
    cout.flush();
    int res;
    cin >> res;
    return res;
}

void solve()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i < n; i++)
    {
        int u, v;
        scanf("%d %d", &u, &v);
        mp[u].emplace_back(v);
        mp[v].emplace_back(u);
    }
    dfs(1, -1);
    int maxx = ask(1, n - 1);
    int l = 1, r = n - 1;
    while (l <= r)
    {
        int mid = l + r >> 1;
        if (ask(l, mid) == maxx)
        {
            r = mid;
            if (l == mid)
            {
                cout << "! " << dfn[l - 1].first << ' ' << dfn[l - 1].second << endl;
                cout.flush();
                return;
            }
        }
        else
            l = mid + 1;
    }
}
int main()
{
    solve();
    return 0;
}

以上是关于CF1592Ddfs序+二分的主要内容,如果未能解决你的问题,请参考以下文章

CF1592D Hemose in ICPC ?

CF1592C Bakry and Partitioning | 异或

CF570D:Tree Requests

[CF1379C] Choosing flowers - 贪心,二分,排序

CF1100E Andrew and Taxi

CF1063D