CodeForces 1174F Ehab and the Big Finale

洛谷传送门

CF 传送门

思路

看到询问次数是 \(O(\log n)\) 级别的,考虑使用树剖的一些性质。

我们都知道一个点到根结点的链经过的轻边为 \(O(\log n)\) 级别的。于是考虑如下的算法:

  1. 先通过一次询问得出 \(x\) 的深度,然后树剖。
  2. 一开始设 \(u \to 1\)。沿着重链跳到和 \(x\) 深度相同的儿子,然后询问它们的 \(\mathrm{LCA}\)\(u \to \mathrm{s}(\mathrm{LCA})\),重复操作直到得出 \(x\) 为止。

注意还有个细节。有可能重链底的点的深度比 \(x\) 小,所以树剖时要特判。

总询问次数为 \(2 \log n + 1\),可以通过。

代码

code
/*

p_b_p_b txdy
AThousandSuns txdy
Wu_Ren txdy
Appleblue17 txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;

int n, head[maxn], len, dx, b[maxn];
int fa[maxn], sz[maxn], son[maxn], dep[maxn], maxd[maxn];

struct edge {
	int to, next;
} edges[maxn << 1];

void add_edge(int u, int v) {
	edges[++len].to = v;
	edges[len].next = head[u];
	head[u] = len;
}

int ask1(int x) {
	printf("d %d\n", x);
	fflush(stdout);
	scanf("%d", &x);
	return x;
}

int ask2(int x) {
	printf("s %d\n", x);
	fflush(stdout);
	scanf("%d", &x);
	return x;
}

int dfs(int u, int f, int d) {
	dep[u] = maxd[u] = d;
	fa[u] = f;
	sz[u] = 1;
	int maxson = -1;
	for (int i = head[u]; i; i = edges[i].next) {
		int v = edges[i].to;
		if (v == f) {
			continue;
		}
		sz[u] += dfs(v, u, d + 1);
		maxd[u] = max(maxd[u], maxd[v]);
		if (sz[v] > maxson && maxd[v] >= dx) {
			son[u] = v;
			maxson = sz[v];
		}
	}
	return sz[u];
}

void solve() {
	scanf("%d", &n);
	for (int i = 1, u, v; i < n; ++i) {
		scanf("%d%d", &u, &v);
		add_edge(u, v);
		add_edge(v, u);
	}
	dx = ask1(1) + 1;
	dfs(1, -1, 1);
	int u = 1;
	while (1) {
		while (dep[u] < dx) {
			b[dep[u]] = u;
			u = son[u];
		}
		int dis = ask1(u);
		if (!dis) {
			printf("! %d\n", u);
			fflush(stdout);
			return;
		}
		int lca = b[dx - dis / 2];
		if (dep[lca] + 1 == dx) {
			printf("! %d\n", ask2(lca));
			fflush(stdout);
			return;
		}
		u = ask2(lca);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2022-07-21 16:35  zltzlt  阅读(32)  评论(0编辑  收藏  举报