Skip to content

Commit 9244055

Browse files
committed
Jump on Tree
1 parent c66ff45 commit 9244055

File tree

2 files changed

+85
-6
lines changed

2 files changed

+85
-6
lines changed

cp-algo/tree/hld.hpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
#include "ascending_dfs.hpp"
44
#include "../graph/base.hpp"
55
#include "../util/big_alloc.hpp"
6-
#include <vector>
7-
#include <ranges>
8-
96
namespace cp_algo::graph {
107
struct heavy_light {
118
big_vector<node_index> size, in, up, par;
@@ -55,15 +52,57 @@ namespace cp_algo::graph {
5552
}
5653
}
5754
}
58-
node_index lca(node_index a, node_index b) {
55+
enum lca_mode { without_distances, with_distances };
56+
template<lca_mode mode = without_distances>
57+
auto lca(node_index a, node_index b) {
58+
int dista = 0, distb = 0;
5959
while (up[a] != up[b]) {
60-
if (in[a] < in[b]) {
60+
if (in[up[a]] < in[up[b]]) {
61+
if constexpr (mode == with_distances) distb += in[b] - in[up[b]] + 1;
6162
b = par[up[b]];
6263
} else {
64+
if constexpr (mode == with_distances) dista += in[a] - in[up[a]] + 1;
6365
a = par[up[a]];
6466
}
6567
}
66-
return in[a] < in[b] ? a : b;
68+
node_index c = in[a] < in[b] ? a : b;
69+
if constexpr (mode == with_distances) {
70+
return std::tuple{c, dista + in[a] - in[c], distb + in[b] - in[c]};
71+
} else {
72+
return c;
73+
}
74+
}
75+
big_vector<node_index> rin;
76+
void compute_rin() {
77+
if (empty(rin)) {
78+
rin.resize(std::size(in));
79+
for (auto [v, inv]: in | std::views::enumerate) {
80+
rin[inv] = node_index(v);
81+
}
82+
}
83+
}
84+
node_index jump_up(node_index v, int steps) {
85+
compute_rin();
86+
while (steps > 0) {
87+
int path_dist = in[v] - in[up[v]];
88+
if (steps <= path_dist) {
89+
return rin[in[v] - steps];
90+
}
91+
steps -= path_dist + 1;
92+
v = par[up[v]];
93+
}
94+
return v;
95+
}
96+
std::optional<node_index> jump(node_index from, node_index to, int steps) {
97+
compute_rin();
98+
auto [l, dist_from, dist_to] = lca<with_distances>(from, to);
99+
auto dist = dist_from + dist_to;
100+
if (steps > dist) return std::nullopt;
101+
if (steps <= dist_from) {
102+
return jump_up(from, steps);
103+
} else {
104+
return jump_up(to, dist - steps);
105+
}
67106
}
68107
};
69108
}

verify/tree/jump.test.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// @brief Jump on Tree
2+
#define PROBLEM "https://judge.yosupo.jp/problem/jump_on_tree"
3+
#pragma GCC optimize("Ofast,unroll-loops")
4+
#include <iostream>
5+
#include "blazingio/blazingio.min.hpp"
6+
#include "cp-algo/tree/hld.hpp"
7+
#include <bits/stdc++.h>
8+
9+
using namespace std;
10+
using namespace cp_algo::graph;
11+
12+
void solve() {
13+
int n, q;
14+
cin >> n >> q;
15+
graph g(n);
16+
g.read_edges(n - 1);
17+
heavy_light hld(g);
18+
for(int i = 0; i < q; i++) {
19+
node_index u, v;
20+
int k;
21+
cin >> u >> v >> k;
22+
auto ores = hld.jump(u, v, k);
23+
if (!ores) {
24+
cout << -1 << '\n';
25+
} else {
26+
cout << *ores << '\n';
27+
}
28+
}
29+
}
30+
31+
signed main() {
32+
//freopen("input.txt", "r", stdin);
33+
ios::sync_with_stdio(0);
34+
cin.tie(0);
35+
int t = 1;
36+
//cin >> t;
37+
while(t--) {
38+
solve();
39+
}
40+
}

0 commit comments

Comments
 (0)