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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hesorchen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值