Last active
December 6, 2021 01:02
-
-
Save MikuroXina/5d098d45373c77ae511d5de15b64c640 to your computer and use it in GitHub Desktop.
The implementation of querying Lowest Common Ancestor.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::num::NonZeroUsize; | |
| /// Calculates the lowest common ancestor on given graph. | |
| #[derive(Debug)] | |
| pub struct LowestCommonAncestor { | |
| parents_by_step: Vec<Vec<Option<NonZeroUsize>>>, | |
| distances: Vec<usize>, | |
| } | |
| impl LowestCommonAncestor { | |
| /// Creates a calculator for the lowest common ancestors. | |
| pub fn new(graph: &[Vec<NonZeroUsize>], root: NonZeroUsize) -> Self { | |
| let vertices = graph.len(); | |
| let max_step = vertices.next_power_of_two(); | |
| let mut parents_by_step = vec![vec![None; vertices + 1]; max_step]; | |
| let mut distances = vec![0; vertices + 1]; | |
| fn dfs( | |
| parents_by_step: &mut Vec<Vec<Option<NonZeroUsize>>>, | |
| distances: &mut Vec<usize>, | |
| graph: &[Vec<NonZeroUsize>], | |
| vertex: NonZeroUsize, | |
| parent: Option<NonZeroUsize>, | |
| distance: usize, | |
| ) { | |
| let vertex_raw = vertex.get(); | |
| parents_by_step[0][vertex_raw] = parent; | |
| distances[vertex_raw] = distance; | |
| for &adj in &graph[vertex_raw] { | |
| if Some(adj) != parent { | |
| dfs( | |
| parents_by_step, | |
| distances, | |
| graph, | |
| adj, | |
| Some(vertex), | |
| distance + 1, | |
| ); | |
| } | |
| } | |
| } | |
| dfs(&mut parents_by_step, &mut distances, graph, root, None, 0); | |
| for step in 0..max_step - 1 { | |
| for vertex in 0..vertices { | |
| parents_by_step[step + 1][vertex] = parents_by_step[step][vertex] | |
| .as_ref() | |
| .and_then(|&parent| parents_by_step[step][parent.get()]); | |
| } | |
| } | |
| Self { | |
| parents_by_step, | |
| distances, | |
| } | |
| } | |
| /// Queries the lowest common ancestor between the vertex `u` and `v`. | |
| pub fn query(&self, u: NonZeroUsize, v: NonZeroUsize) -> NonZeroUsize { | |
| let mut u = u.get(); | |
| let mut v = v.get(); | |
| if self.distances[u] < self.distances[v] { | |
| std::mem::swap(&mut u, &mut v); | |
| } | |
| let max_step = self.parents_by_step.len(); | |
| for k in 0..max_step { | |
| if (self.distances[u] - self.distances[v]) >> k & 1 == 1 { | |
| u = self.parents_by_step[k][u].unwrap().get(); | |
| } | |
| } | |
| if u == v { | |
| return NonZeroUsize::new(u).unwrap(); | |
| } | |
| for k in (0..max_step).rev() { | |
| if self.parents_by_step[k][u] != self.parents_by_step[k][v] { | |
| u = self.parents_by_step[k][u].unwrap().get(); | |
| v = self.parents_by_step[k][v].unwrap().get(); | |
| } | |
| } | |
| self.parents_by_step[0][u].unwrap() | |
| } | |
| /// Calculates the distance between the vertex `u` and `v`. | |
| pub fn dist(&self, u: NonZeroUsize, v: NonZeroUsize) -> usize { | |
| let root_dist = self.distances[self.query(u, v).get()]; | |
| let u = u.get(); | |
| let v = v.get(); | |
| self.distances[u] + self.distances[v] - 2 * root_dist | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment