Skip to content

Commit 7f90dc2

Browse files
Next on path (#96)
* convert * converted RMQ * fix * fix * nit * actually let's do fnmut * Revert "actually let's do fnmut" This reverts commit 946ebfd. * saving progress * fix * fix docs * add extra examples * nit * fix bug * actually this is better * Update lca.rs --------- Co-authored-by: Luke Videckis <lukevideckis@gmail.com> Co-authored-by: Cameron Custer <73217097+cameroncuster@users.noreply.github.com>
1 parent 49a8ece commit 7f90dc2

File tree

3 files changed

+119
-4
lines changed

3 files changed

+119
-4
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,7 @@ path = "examples/monotonic/count_rects.rs"
215215
[[example]]
216216
name = "cartesian_tree"
217217
path = "examples/monotonic/cartesian_tree.rs"
218+
219+
[[example]]
220+
name = "lca_rmq_next_on_path"
221+
path = "examples/graphs/lca_rmq_next_on_path.rs"
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// verification-helper: PROBLEM https://judge.yosupo.jp/problem/tree_diameter
2+
3+
use proconio::input;
4+
use programming_team_code_rust::graphs::lca::LCA;
5+
6+
fn main() {
7+
input! {
8+
n: usize,
9+
}
10+
11+
let mut adj = vec![vec![]; n];
12+
let mut adj_w = vec![vec![]; n];
13+
for _ in 1..n {
14+
input! {
15+
u: usize,
16+
v: usize,
17+
w: i64,
18+
}
19+
adj[u].push(v);
20+
adj[v].push(u);
21+
adj_w[u].push((v, w));
22+
adj_w[v].push((u, w));
23+
}
24+
25+
let lca = LCA::new(&adj);
26+
27+
let mut dist_root = vec![0; n];
28+
fn dfs(u: usize, p: Option<usize>, adj_w: &[Vec<(usize, i64)>], dist_root: &mut Vec<i64>) {
29+
for &(v, w) in &adj_w[u] {
30+
if Some(v) == p {
31+
continue;
32+
}
33+
dist_root[v] = w + dist_root[u];
34+
dfs(v, Some(u), adj_w, dist_root);
35+
}
36+
}
37+
38+
dfs(0, None, &adj_w, &mut dist_root);
39+
40+
let dist_path =
41+
|u: usize, v: usize| -> i64 { dist_root[u] + dist_root[v] - 2 * dist_root[lca.lca(u, v)] };
42+
43+
let mut u = 0;
44+
for i in 1..n {
45+
if dist_path(0, u) < dist_path(0, i) {
46+
u = i;
47+
}
48+
}
49+
50+
let mut v = 0;
51+
for i in 1..n {
52+
if dist_path(u, v) < dist_path(u, i) {
53+
v = i;
54+
}
55+
}
56+
57+
println!("{} {}", dist_path(u, v), lca.dist(u, v) + 1);
58+
59+
print!("{} ", u);
60+
while u != v {
61+
u = lca.next_on_path(u, v);
62+
print!(" {}", u);
63+
}
64+
println!();
65+
}

src/graphs/lca.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::data_structures::rmq::RMQ;
44
use crate::graphs::dfs_order::get_dfs_preorder;
55

6-
type OpType = fn(&(usize, usize), &(usize, usize)) -> (usize, usize);
6+
type Pair = (usize, usize);
77

88
/// # Example
99
/// ```
@@ -19,11 +19,17 @@ type OpType = fn(&(usize, usize), &(usize, usize)) -> (usize, usize);
1919
/// let lca = LCA::new(&adj);
2020
/// assert_eq!(lca.lca(1, 3), 0);
2121
/// assert_eq!(lca.lca(2, 3), 2);
22+
/// assert_eq!(lca.dist(1, 3), 3);
23+
/// assert_eq!(lca.in_sub(2, 3), true);
24+
/// assert_eq!(lca.next_on_path(0, 3), 2);
25+
/// assert!(std::panic::catch_unwind(|| lca.next_on_path(1, 1)).is_err());
2226
/// ```
2327
pub struct LCA {
2428
tin: Vec<usize>,
2529
p: Vec<Option<usize>>,
26-
rmq: RMQ<(usize, usize), OpType>,
30+
d: Vec<usize>,
31+
siz: Vec<usize>,
32+
rmq: RMQ<Pair, fn(&Pair, &Pair) -> Pair>,
2733
}
2834

2935
impl LCA {
@@ -49,13 +55,21 @@ impl LCA {
4955
}
5056
}
5157
}
58+
let mut siz = vec![1; n];
59+
for &u in order.iter().rev() {
60+
if let Some(par) = p[u] {
61+
siz[par] += siz[u];
62+
}
63+
}
5264
LCA {
53-
tin,
5465
p,
5566
rmq: RMQ::new(
5667
&order.iter().map(|&u| (d[u], u)).collect::<Vec<_>>(),
57-
|&x, &y| std::cmp::min(x, y),
68+
|&x, &y| if x.0 < y.0 { x } else { y },
5869
),
70+
d,
71+
tin,
72+
siz,
5973
}
6074
}
6175

@@ -74,4 +88,36 @@ impl LCA {
7488
}
7589
self.p[self.rmq.query(le + 1..ri + 1).1].unwrap()
7690
}
91+
92+
/// Gets number of edges on path from u to v
93+
///
94+
/// # Complexity
95+
/// - Time: O(1)
96+
/// - Space: O(1)
97+
pub fn dist(&self, u: usize, v: usize) -> usize {
98+
self.d[u] + self.d[v] - 2 * self.d[self.lca(u, v)]
99+
}
100+
101+
/// Returns true iff v is in u's subtree
102+
///
103+
/// # Complexity
104+
/// - Time: O(1)
105+
/// - Space: O(1)
106+
pub fn in_sub(&self, u: usize, v: usize) -> bool {
107+
(self.tin[u]..self.tin[u] + self.siz[u]).contains(&self.tin[v])
108+
}
109+
110+
/// Gets \[u, p\[u\], .., lca(u,v), .., p\[v\], v\]\[1\]
111+
///
112+
/// # Complexity
113+
/// - Time: O(1)
114+
/// - Space: O(1)
115+
pub fn next_on_path(&self, u: usize, v: usize) -> usize {
116+
assert!(u != v);
117+
if self.in_sub(u, v) {
118+
self.rmq.query(self.tin[u] + 1..self.tin[v] + 1).1
119+
} else {
120+
self.p[u].unwrap()
121+
}
122+
}
77123
}

0 commit comments

Comments
 (0)