安吉D11-D
- 1安吉D19 T1
- 2安吉D19 T3
- 3安吉D20 模考12总结
- 4安吉D17 T3
- 5安吉D17 T4
- 6安吉D19 模考11总结
- 7安吉D15 A
- 8安吉D16 T4
- 9安吉D17 T1
- 10安吉D17 模考10总结
- 11安吉D16 T3
- 12安吉D16 模考9总结
- 13安吉D13 模考8总结
- 14安吉D13-T2
- 15安吉D13-T3
- 16安吉D12-T3
- 17安吉D11-B
- 18安吉D11-C
- 19安吉D11-D本文
- 20安吉D12 模考7总结
- 21安吉D12-T2
- 22安吉D11-A
- 23安吉D10 模考6总结
- 24安吉D10-T3
- 25安吉D10-T4
- 26安吉D8-E
- 27安吉D9-T4
- 28安吉D8-A
- 29安吉D8-B
- 30安吉D8-C
- 31安吉D8-D
- 32安吉D9 模考5总结
- 33安吉D9-T2
- 34安吉D9-T3
- 35安吉D6-T4
- 36安吉D4-G
- 37安吉D5-T2
- 38安吉D6 模考4总结
- 39安吉D6-T1
- 40安吉D6-T3
- 41安吉-开营测试 T4
- 42安吉D5 模考3总结
- 43安吉D5-T3
- 44安吉D4-A
- 45安吉D4-B
- 46安吉D4-C
- 47安吉D4:容斥原理
- 48安吉Day4-D
- 49安吉D3 模考2总结
- 50安吉D3-T1
- 51安吉D3-T2
- 52安吉D3-T4
- 53安吉D2 模考1总结
- 54安吉D2-T2
- 55安吉D1-G
- 56安吉D1-L
- 57安吉D2-T4
原题呈现
Codeforces 2193G - Paths in a Tree
题目描述
本题为交互式题目.
给你一个无环连通的无向图,包含 个顶点. 定义一条从顶点 到顶点 的路径为一个由互不相同的顶点组成的序列 ,满足 ,,并且对于所有 (),顶点 与 之间都存在一条边.
图中有两个隐藏的顶点 和 (它们可能相同).你可以进行如下询问:
- 选择两个顶点 (). 交互库会返回 ,如果从 到 的路径与从 到 的路径至少有一个公共顶点;否则返回 .
你的任务是在不超过 次询问内,找到至少一个位于 到 路径上的顶点.
注意:交互库是自适应的,这意味着隐藏的顶点可能会根据你的询问而改变,但不会与先前的回答矛盾.
输入格式
每个测试包含多个测试用例. 第一行包含一个整数 ()—— 测试用例的数量.接下来的行描述每个测试用例.
每个测试用例的第一行包含一个整数 ()—— 图中顶点个数.
接下来 行,每行包含两个整数 (),表示顶点 和 之间有一条边.
保证所有测试用例的 之和不超过 .
交互过程
为了找到路径上的顶点,你最多可以使用 次询问.
询问格式为 ? a b.
每次询问后,读入一个整数,即返回的 或 .
当你找到一个满足要求的顶点时,输出一行 ! v(),其中 是你找到的顶点.
如果你的程序对某个测试用例发出了超过 次询问,那么交互库会返回 .在收到这样的回答后,你的程序应该立即终止,否则将得到“答案错误”的评判.否则,它可能会得到其他评判结果.
输出询问后,记得输出换行并刷新输出缓冲区,否则你会收到“超时”的评判.
在 C++ 中可使用 fflush(stdout) 或 cout.flush();在 Java 中可使用 System.out.flush();在 Python 中可使用 stdout.flush();其他语言请参考相应文档.
样例
输入
3
21 2
1
31 21 3
0
0
41 22 32 4
0
1输出
? 1 1
! 1
? 1 1
? 2 2
! 3
? 1 3
? 4 4
! 4首先,观察到询问次数的限制是 ,这说明我们每次至少要排除两个节点.
有以下一个结论:我们可以按照 dfn 次序,每一次询问 dfn 最靠前的两个没有被询问过的节点.如果回答是 Yes,则再花一次询问分出是询问的两个点其中哪一个点.如果回答 No 则接着询问另外两个 dfn 最靠前且没有被询问过的节点
为什么是这样呢?我们观察 dfn 连续的两个节点,发现它们只会存在两种位置关系:
- 一条边的两个顶点(如下图的 ,)
- 分居于一个节点的两颗子树(如下图的 ,)
对于第一种情况,由于本身就是一条边,不会有其他点干扰.因此,可以稳定地排除两个点;对于第二种情况,我们可以发现,对于一对点,其路径上的其他点必然在前面的询问中已经排除了.如 这一对点,其路径上的 都已经在前面的询问中被排除过了.因此也可以稳定地排除两个点.
标程
#include <bits/stdc++.h>using namespace std;const int N = 2e5 + 100;int n, dfn[N], cnt, id[N];vector<int> e[N];
void dfs(int u, int fa) { dfn[u] = ++cnt; id[dfn[u]] = u; for (auto v : e[u]) { if (v != fa) dfs(v, u); }}
void solve() { for (int i = 1; i <= n; ++i) e[i].clear(); cin >> n; cnt = 0; int root = -1; for (int i = 1; i <= n - 1; i++) { int u, v; cin >> u >> v; if (root == -1) { root = u; } e[u].push_back(v); e[v].push_back(u); } dfs(root, 0); for (int i = 1; i + 1 <= n; i += 2) { cout << "? " << id[i] << " " << id[i + 1] << endl; cout.flush(); int res; cin >> res; if (res == 1) { cout << "? " << id[i] << " " << id[i] << endl; cout.flush(); cin >> res; if (res) { cout << "! " << id[i] << endl; cout.flush(); return; } else { cout << "! " << id[i + 1] << endl; cout.flush(); return; } } } cout << "! " << id[n] << endl; cout.flush();}
signed main() { int t; cin >> t; while (t--) { solve(); } return 0;}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!


