题解 CF1305D 【Kuroni and the Celebration】

xht

2020-03-06 13:16:23

Solution

每次询问两个点的 LCA,最多询问 $\lfloor \frac{n}{2} \rfloor$ 次确定根。 很傻的一道交互题。 注意到如果一个叶子和另一个点的 LCA 就是这个叶子,那么这个叶子一定为根;如果不是,则这个叶子一定不是根。 那么我们每次询问两个叶子的 LCA 即可,如果是其中某一个点,则那个点就是根;否则删掉两个点,注意可能产生新的叶子。 最坏情况下,每次询问会删掉两个叶子,那么 $\lfloor \frac{n}{2} \rfloor$ 次后最多只剩下一个点,这个点显然就是根了。 ```cpp const int N = 1e3 + 7; int n, d[N], v[N]; vi e[N]; int main() { ios::sync_with_stdio(0); cin >> n; for (int i = 1, x, y; i < n; i++) cin >> x >> y, e[x].pb(y), e[y].pb(x), d[x]++, d[y]++; queue<int> q; for (int i = 1; i <= n; i++) if (d[i] == 1) q.push(i); for (int i = 1; i <= n / 2; i++) { int x = q.front(); q.pop(); int y = q.front(); q.pop(); cout << "? " << x << " " << y << endl; fflush(stdout); int z; cin >> z; if (z == x || z == y) { cout << "! " << z << endl; return 0; } for (int z : e[x]) if (!v[z] && (--d[z] == 1)) q.push(z); for (int z : e[y]) if (!v[z] && (--d[z] == 1)) q.push(z); v[x] = v[y] = 1; } for (int i = 1; i <= n; i++) if (!v[i]) cout << "! " << i << endl; return 0; } ```