前言
- 参考博客:oi-wiki
- 题目1要求:对欧拉序有个基本的印象先吧,然后多刷题!!
欧拉序介绍
题目
题目1:欧拉序(任意一段序列所表示的边都是其中所有点中的几个点之间的简单路径)
- 传送门:D. Hemose in ICPC ?
- 题意:给定一棵节点数为
n
≤
3000
n\le 3000
n≤3000 的树,边权不知道,最多12次询问,每次询问返回这些点路径的中边权的最大公因子(其实就是返回这些边的所有简单路径中的最大边权)。求边权最大的边(返回两个值 u ,v ,其中 u-v 边为树中最大边),如果有多个答案,返回任意一个。
- 题解:
- 提示:欧拉序。
- 另外,前人总结:交互问题,不是二分就是分块。
- 代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 100;
int n, u, v;
vector<int> g[N];
vector<int> b;
int cnt = 0, a[N];
void dfs(int x, int fa) {
for (auto i : g[x]) {
if (i == fa) continue;
a[++cnt] = i;
dfs(i, x);
a[++cnt] = x;
}
}
int query() {
sort(b.begin(), b.end());
b.erase(unique(b.begin(), b.end()), b.end());
int sz = b.size();
printf("? %d", sz);
fflush(stdout);
for (int i = 0; i < sz; i++) printf(" %d", b[i]), fflush(stdout);
printf("\n");
fflush(stdout);
int x;
scanf("%d", &x);
return x;
}
signed main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
g[u].push_back(v), g[v].push_back(u);
}
a[++cnt] = 1;
dfs(1, -1);
b.clear();
for (int i = 1; i <= cnt; i++) b.push_back(a[i]);
int mx = query();
int l = 1, r = cnt;
while (l + 1 < r) {
int mid = (l + r) >> 1;
b.clear();
for (int i = l; i <= mid; i++) b.push_back(a[i]);
if (query() < mx)
l = mid;
else
r = mid;
}
printf("! %d %d\n", a[l], a[r]);
fflush(stdout);
return 0;
}