CF1592Ddfs序+二分
Posted hesorchen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1592Ddfs序+二分相关的知识,希望对你有一定的参考价值。
题目
交互题。
给出一棵树,点数<=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序+二分的主要内容,如果未能解决你的问题,请参考以下文章
CF1592C Bakry and Partitioning | 异或