Codeforces1592D Hemose in ICPC ? (欧拉序)

99 篇文章 2 订阅
14 篇文章 0 订阅

题目链接: Hemose in ICPC ?

大致题意

给定一棵有 n n n个顶点, n − 1 n - 1 n1条边的树.

定义: D i s t ( a , b ) = a , b 两 点 间 路 径 的 g c d 的 最 大 值 . Dist(a, b) = a, b两点间路径的gcd的最大值. Dist(a,b)=a,bgcd.

我们可以进行最多 12 12 12次询问, 每次询问给出一个点集, 系统会返回当前点集的所有点对中的最大 D i s t Dist Dist.

最终需要输出两个点 a , b a, b a,b, 要求最大化 D i s t ( a , b ) Dist(a, b) Dist(a,b).

解题思路

思维

我们首先对题目进行转化, 我们要求最大的 D i s t ( a , b ) Dist(a, b) Dist(a,b), 而 D i s t Dist Dist的求法是不断进行 g c d gcd gcd运算, 由于 g c d gcd gcd运算是只减不增的, 因此题目等价于求出两个点 a , b a, b a,b, 满足连接这两个点的边权是最大的.

同理, 每次询问时, 系统返回的答案我们可以看作是当前点集中的最大边权.


欧拉序

很显然, 我们首先对于所有点进行一次询问, 这样我们得到的 D m a x Dmax Dmax就是所求. 此时我们剩余 11 11 11次询问.

我们考虑到最大边权一定出现在两点之间, 因此不妨求出整棵树的欧拉序, 考虑在欧拉序上二分即可.

由于点最多有 1000 1000 1000个, 因此欧拉序最长为 1999 1999 1999, 我们可以在 11 11 11次询问后求得.

AC代码

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E3 + 10;
vector<int> edge[N];

int oula[N * 2], ind;
void dfs(int x, int fa) {
	for (auto& to : edge[x]) {
		if (to == fa) continue;
		oula[++ind] = to;
		dfs(to, x);
		oula[++ind] = x;
	}
}
int main()
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

	int n; cin >> n;
	rep(i, n - 1) {
		int a, b; cin >> a >> b;
		edge[a].push_back(b);
		edge[b].push_back(a);
	}

	oula[++ind] = 1;
	dfs(1, 0);

	auto ask = [](int l, int r) {
		set<int> st; //去重这部分区间的欧拉序
		for (int i = l; i <= r; ++i) st.insert(oula[i]);
		cout << "? " << st.size() << ' ';
		for (auto& op : st) cout << op << ' ';
		cout << endl;

		int res; cin >> res;
		return res;
	};

	int target = ask(1, ind);
	int l = 1, r = ind;
	while (l + 1 < r) {
		int mid = l + r >> 1;
		if (ask(l, mid) == target) r = mid;
		else l = mid;
	}

	cout << "! " << oula[l] << ' ' << oula[r] << endl;

	return 0;
}

END

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逍遥Fau

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

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

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

打赏作者

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

抵扣说明:

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

余额充值