题解:P12393 「RiOI-6」flos

\(\text{Upd 2025/5/2}\):修正一些笔误,简化了做法。

\(\text{Upd 2025/5/16}\):走直径的做法假了,改为正确做法。

题意

给定一棵以 \(1\) 为根的树。一个人从 \(x\) 出发,有 \(t\) 秒的时间,往远离根方向每走一个单位就会耗费 \(1\) 秒,往靠近根方向走不耗费时间。\(q\) 次询问 \(x,t\),求能走到的最远的距离。\(1\leq n,q\leq 2\times 10^5\)强制在线

题解

之前走直径的做法假完了,补一发正解。

我们的策略必然是先向上走一段,然后一直向下走。首先考虑一直向上走和一直向下走的情况,此时答案为 \(\max(dep_x-1,\min(f_x,t))\),其中 \(dep_1=1\)\(f_u\) 表示从点 \(u\) 向下走能走到的最远距离。

接下来令 \(g_u\) 表示从 \(fa_u\) 开始不经过 \(u\) 能走到的最远距离,则答案就是

\[\max_{fa_u\in anc(x)}\{dep_x-dep_{fa_u}+\min(t,g_u)\} \]

\(\min\)

  • \(g_u\geq t\):我们只需取深度最小的 \(u\)。预处理 \(G_u\) 表示 \(u\) 到根节点的链上的 \(g\) 的最大值,树上倍增跳出深度最小的点 \(p\) 即可。
  • \(g_u<t\):显然 \(u\) 必须是 \(v\) 的祖先,否则必然不优,于是预处理 \(h_u\) 表示 \(u\) 到根节点的链上的 \(g_v-dep_{fa_v}\) 的最大值即可。

时间复杂度 \(\mathcal{O}(n\log{n})\)

代码

#include <iostream>
#include <cstring>

using namespace std;

#define lowbit(x) ((x) & -(x))
#define chk_min(x, v) (x) = min((x), (v))
#define chk_max(x, v) (x) = max((x), (v))
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 5, LGN = 18 + 5, INF = 1e9;

int n, q, d, ans, f[N][2], g[N], mxg[N], h[N];
int lg2[N], dep[N], fa[LGN][N];

struct AdjList {
	int tot, head[N], nxt[N << 1], to[N << 1];
	inline void init(int n) {
		tot = 0;
		for (int i = 1; i <= n; ++i) head[i] = -1;
	}
	inline void ins(int x, int y) { to[++tot] = y, nxt[tot] = head[x], head[x] = tot; }
} tree;

inline void init(int n) {
	for (int i = 2; i <= n; ++i) lg2[i] = lg2[i >> 1] + 1;
	for (int i = 1; i <= n; ++i) h[i] = -INF;
	tree.init(n);
}
inline void dfs1(int x) {
	for (int i = 1; i <= lg2[dep[x]]; ++i) fa[i][x] = fa[i - 1][fa[i - 1][x]];
	for (int i = tree.head[x]; ~i; i = tree.nxt[i]) {
		int y = tree.to[i];
		if (y == fa[0][x]) continue;
		fa[0][y] = x, dep[y] = dep[x] + 1, dfs1(y);
		if (f[y][0] + 1 > f[x][0]) f[x][1] = f[x][0], f[x][0] = f[y][0] + 1;
		else chk_max(f[x][1], f[y][0] + 1);
	}
}
inline void dfs2(int x) {
	for (int i = tree.head[x]; ~i; i = tree.nxt[i]) {
		int y = tree.to[i];
		if (y == fa[0][x]) continue;
		g[y] = f[x][(f[y][0] + 1) == f[x][0]], mxg[y] = max(mxg[x], g[y]);
		h[y] = max(h[x], g[y] - dep[x]);
		dfs2(y);
	}
}
inline int query(int x, int t) {
	for (int i = lg2[dep[x]]; i >= 0; --i)
		if (mxg[fa[i][x]] >= t) x = fa[i][x];
	return fa[0][x];
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> q >> d, init(n);
    for (int i = 1, u, v; i < n; ++i) cin >> u >> v, tree.ins(u, v), tree.ins(v, u);
    dep[1] = 1, dfs1(1), dfs2(1);
    while (q--) {
    	int x, t; cin >> x >> t;
    	if (d) x ^= ans, t ^= ans;
    	if (x == 1) ans = min(t, f[x][0]);
    	else if (!t) ans = dep[x] - 1;
    	else if (mxg[x] < t) ans = max(min(t, f[x][0]), dep[x] + h[x]);
    	else {
	    	int y = query(x, t);
	    	ans = max(min(t, f[x][0]), dep[x] - 1);
	    	if (y) chk_max(ans, dep[x] + max(h[y], t - dep[y]));
    	}
    	cout << ans << '\n';
    }
    return 0;
}
posted @ 2025-05-04 18:04  P2441M  阅读(19)  评论(0)    收藏  举报