Skip to content

Commit 71edca8

Browse files
cameroncusterweb-flowlrvideckis
authored
add lca (#17)
* add lca * [auto-verifier] verify commit ae428c9 * now lint with clippy * consistency * asdf * install verifyer helper tool later * fix unused var * revert * add back in clippy * fix clippy warnings * [auto-verifier] verify commit f96bc61 * better way * [auto-verifier] verify commit bc8f6ea * now it ACs * [auto-verifier] verify commit 9ec9d52 * here's some version which passes clippy * revert some * [auto-verifier] verify commit f8ffdd7 * fix clippy * [auto-verifier] verify commit d7c0c42 * remove todo * [auto-verifier] verify commit df31aaf * revert * less diff * [auto-verifier] verify commit 22d5e9f * new CI file * set up rust * [auto-verifier] verify commit 15ead42 * increase time limit * only build as we use oj verify to test * [auto-verifier] verify commit 13d63c5 * to test CI * revert * no longer keep timestamp file since all tests will run each time --------- Co-authored-by: GitHub <noreply@github.com> Co-authored-by: Luke Videckis <lukevideckis@gmail.com>
1 parent 7f2d269 commit 71edca8

File tree

3 files changed

+84
-0
lines changed

3 files changed

+84
-0
lines changed

examples/lca.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// verification-helper: PROBLEM https://judge.yosupo.jp/problem/lca
2+
3+
use proconio::input;
4+
use programming_team_code_rust::lca::LCA;
5+
6+
fn main() {
7+
input! {
8+
n: usize,
9+
q: usize,
10+
p: [usize; n - 1],
11+
queries: [(usize, usize); q],
12+
}
13+
14+
let mut adj = vec![vec![]; n + n];
15+
for (i, &parent) in p.iter().enumerate() {
16+
adj[parent].push(i + 1);
17+
adj[i + 1].push(parent);
18+
adj[n + parent].push(n + i + 1);
19+
}
20+
21+
let lca = LCA::new(&adj);
22+
for (u, v) in queries {
23+
let res = lca.lca(u, v);
24+
let res_other = lca.lca(n + u, n + v) - n;
25+
assert!(res == res_other);
26+
println!("{}", res);
27+
}
28+
}

src/lca.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use crate::rmq::RMQ;
2+
3+
pub struct LCA {
4+
tin: Vec<usize>,
5+
p: Vec<Option<usize>>,
6+
rmq: RMQ<(usize, usize)>,
7+
}
8+
impl LCA {
9+
/// adj can be undirected tree, directed tree (rooted at node 0), or a forest of undirected
10+
/// trees
11+
pub fn new(adj: &Vec<Vec<usize>>) -> Self {
12+
let n = adj.len();
13+
let mut d = vec![0; n];
14+
let mut tin = vec![0; n];
15+
let mut p = vec![None; n];
16+
let mut order = Vec::with_capacity(n);
17+
fn dfs(
18+
u: usize,
19+
p: &mut Vec<Option<usize>>,
20+
adj: &Vec<Vec<usize>>,
21+
d: &mut Vec<usize>,
22+
tin: &mut Vec<usize>,
23+
order: &mut Vec<usize>,
24+
) {
25+
tin[u] = order.len();
26+
order.push(u);
27+
for &v in &adj[u] {
28+
if p[u] != Some(v) {
29+
d[v] = d[u] + 1;
30+
p[v] = Some(u);
31+
dfs(v, p, adj, d, tin, order);
32+
}
33+
}
34+
}
35+
for s in 0..n {
36+
if p[s].is_none() {
37+
dfs(s, &mut p, adj, &mut d, &mut tin, &mut order);
38+
}
39+
}
40+
let d_with_order: Vec<(usize, usize)> = order.iter().map(|&u| (d[u], u)).collect();
41+
let rmq = RMQ::new(&d_with_order, std::cmp::min);
42+
LCA { tin, p, rmq }
43+
}
44+
/// gets the lowest common ancestor of u and v
45+
pub fn lca(&self, u: usize, v: usize) -> usize {
46+
if u == v {
47+
return u;
48+
}
49+
let (mut le, mut ri) = (self.tin[u], self.tin[v]);
50+
if le > ri {
51+
std::mem::swap(&mut le, &mut ri);
52+
}
53+
self.p[self.rmq.query(le + 1..ri + 1).1].unwrap()
54+
}
55+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod dijk;
22
pub mod dsu;
33
pub mod fenwick;
4+
pub mod lca;
45
pub mod rmq;

0 commit comments

Comments
 (0)