結果
問題 | No.2563 色ごとのグループ |
ユーザー | atcoder8 |
提出日時 | 2023-12-02 16:06:52 |
言語 | Rust (1.77.0 + proconio) |
結果 |
AC
|
実行時間 | 95 ms / 2,000 ms |
コード長 | 12,890 bytes |
コンパイル時間 | 14,879 ms |
コンパイル使用メモリ | 379,380 KB |
実行使用メモリ | 20,380 KB |
最終ジャッジ日時 | 2024-09-26 19:50:45 |
合計ジャッジ時間 | 17,447 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
5,248 KB |
testcase_01 | AC | 1 ms
5,248 KB |
testcase_02 | AC | 1 ms
5,376 KB |
testcase_03 | AC | 1 ms
5,376 KB |
testcase_04 | AC | 1 ms
5,376 KB |
testcase_05 | AC | 1 ms
5,376 KB |
testcase_06 | AC | 1 ms
5,376 KB |
testcase_07 | AC | 1 ms
5,376 KB |
testcase_08 | AC | 1 ms
5,376 KB |
testcase_09 | AC | 1 ms
5,376 KB |
testcase_10 | AC | 1 ms
5,376 KB |
testcase_11 | AC | 1 ms
5,376 KB |
testcase_12 | AC | 1 ms
5,376 KB |
testcase_13 | AC | 1 ms
5,376 KB |
testcase_14 | AC | 1 ms
5,376 KB |
testcase_15 | AC | 1 ms
5,376 KB |
testcase_16 | AC | 2 ms
5,376 KB |
testcase_17 | AC | 1 ms
5,376 KB |
testcase_18 | AC | 1 ms
5,376 KB |
testcase_19 | AC | 2 ms
5,376 KB |
testcase_20 | AC | 6 ms
5,376 KB |
testcase_21 | AC | 4 ms
5,376 KB |
testcase_22 | AC | 3 ms
5,376 KB |
testcase_23 | AC | 5 ms
5,376 KB |
testcase_24 | AC | 41 ms
9,952 KB |
testcase_25 | AC | 37 ms
10,296 KB |
testcase_26 | AC | 58 ms
14,268 KB |
testcase_27 | AC | 74 ms
17,224 KB |
testcase_28 | AC | 65 ms
15,888 KB |
testcase_29 | AC | 95 ms
20,380 KB |
testcase_30 | AC | 91 ms
20,380 KB |
testcase_31 | AC | 92 ms
20,124 KB |
testcase_32 | AC | 93 ms
20,256 KB |
testcase_33 | AC | 92 ms
16,796 KB |
testcase_34 | AC | 89 ms
16,924 KB |
testcase_35 | AC | 92 ms
17,052 KB |
testcase_36 | AC | 91 ms
16,924 KB |
testcase_37 | AC | 91 ms
16,924 KB |
ソースコード
use union_find::UnionFind; fn main() { let (n, m) = { let mut line = String::new(); std::io::stdin().read_line(&mut line).unwrap(); let mut iter = line.split_whitespace(); ( iter.next().unwrap().parse::<usize>().unwrap(), iter.next().unwrap().parse::<usize>().unwrap(), ) }; let cc: Vec<_> = { let mut line = String::new(); std::io::stdin().read_line(&mut line).unwrap(); line.split_whitespace() .map(|x| x.parse::<usize>().unwrap() - 1) .collect() }; let uv: Vec<_> = (0..m) .map(|_| { let mut line = String::new(); std::io::stdin().read_line(&mut line).unwrap(); let mut iter = line.split_whitespace(); ( iter.next().unwrap().parse::<usize>().unwrap() - 1, iter.next().unwrap().parse::<usize>().unwrap() - 1, ) }) .collect(); let mut uf = UnionFind::new(n); for &(u, v) in &uv { if cc[u] == cc[v] { uf.merge(u, v); } } let mut groups = vec![vec![]; n]; for (i, &c) in cc.iter().enumerate() { groups[c].push(i); } let mut ans = 0; for group in &groups { for &node in group { ans += uf.merge(group[0], node) as usize; } } println!("{}", ans); } pub mod union_find { //! Union-Find processes the following queries on undirected graphs. //! * Merge two connected components. //! * Determine whether two given nodes are in the same connected component. //! //! To seed up processing, merge optimization using the number of nodes //! of the connected components and path compression are performed. //! //! The time complexity of each query is `O(A(n))`. //! where `n` is the number of nodes in the graph and //! `A(n)` is the inverse of the Ackermann function. /// This is the value that will be associated with each nodes of the graph. #[derive(Debug, Clone, Copy)] enum ParentOrSize { /// It is used for non-representative nodes and stores the parent node. Parent(usize), /// It is used for the representative node and /// stores the number of nodes of the connected component. Size(usize), } /// Union-Find processes the following queries on undirected graphs. /// * Merge two connected components. /// * Determine whether two given nodes are in the same connected component. /// /// To seed up processing, merge optimization using the number of nodes /// of the connected components and path compression are performed. /// /// The time complexity of each query is `O(A(n))`. /// where `n` is the number of nodes in the graph and /// `A(n)` is the inverse of the Ackermann function. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(3); /// assert_eq!(uf.same(0, 2), false); /// uf.merge(0, 1); /// assert_eq!(uf.same(0, 2), false); /// uf.merge(1, 2); /// assert_eq!(uf.same(0, 2), true); /// ``` #[derive(Debug, Default, Clone)] pub struct UnionFind { /// For each node, one of the following is stored. /// * The number of nodes of the connected component to which it belongs. /// (If it is a representative node of the connected component.) /// * Index of the parent node. (Otherwise.) parent_or_size: Vec<ParentOrSize>, /// Number of connected components. group_num: usize, } impl UnionFind { /// Create an undirected graph with `n` nodes and `0` edges. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(3); /// assert_eq!(uf.same(0, 2), false); /// uf.merge(0, 1); /// assert_eq!(uf.same(0, 2), false); /// uf.merge(2, 1); /// assert_eq!(uf.same(0, 2), true); /// ``` pub fn new(n: usize) -> Self { UnionFind { parent_or_size: vec![ParentOrSize::Size(1); n], group_num: n, } } /// Return the representative node of the connected component containing node `a`. /// /// At that time, perform path compression on the nodes on the path from node `a` to the representative node. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(3); /// uf.merge(1, 2); /// assert_eq!(uf.leader(0), 0); /// assert_eq!(uf.leader(1), uf.leader(2)); /// ``` pub fn leader(&mut self, a: usize) -> usize { // If node `a` is a representative node of the connected component, return `a`. if let ParentOrSize::Size(_) = self.parent_or_size[a] { return a; } // Path from node `a` to the representative node. let mut path = vec![]; // Current node. let mut current = a; // Record the path to the representative node. while let ParentOrSize::Parent(parent) = self.parent_or_size[current] { // Add current node to the path. path.push(current); // Move to the parent node. current = parent; } // The representative node of the connected component. let leader = current; // Set nodes on the path as direct children of the representative node. path.iter().for_each(|&node| { self.parent_or_size[node] = ParentOrSize::Parent(leader); }); // Return the representative node of the connected component. leader } /// Return whether two nodes `a` and `b` are in the same connected component. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(3); /// assert_eq!(uf.same(0, 2), false); /// uf.merge(0, 1); /// assert_eq!(uf.same(0, 2), false); /// uf.merge(2, 1); /// assert_eq!(uf.same(0, 2), true); /// ``` pub fn same(&mut self, a: usize, b: usize) -> bool { self.leader(a) == self.leader(b) } /// Merge each connected component containing nodes `a` and `b`. /// /// Return `true` if different connected components are newly merged. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(3); /// assert_eq!(uf.same(0, 2), false); /// uf.merge(0, 1); /// assert_eq!(uf.same(0, 2), false); /// uf.merge(2, 1); /// assert_eq!(uf.same(0, 2), true); /// ``` pub fn merge(&mut self, a: usize, b: usize) -> bool { // Representative node of the connected component that contains the node `a`. let leader_a = self.leader(a); // Representative node of the connected component that contains the node `b`. let leader_b = self.leader(b); // If nodes `a` and `b` are in the same connected component, return `false` without processing. if leader_a == leader_b { return false; } // Number of nodes of the component containing node `a`. let component_size_a = self.size(leader_a); // Number of nodes of the component containing node `b`. let component_size_b = self.size(leader_b); // Number of nodes of the merged component. let merged_component_size = component_size_a + component_size_b; // Set the parent of the representative node of the smaller sized connected component // to be the parent of the other connected component. if component_size_a <= component_size_b { self.parent_or_size[leader_a] = ParentOrSize::Parent(leader_b); self.parent_or_size[leader_b] = ParentOrSize::Size(merged_component_size); } else { self.parent_or_size[leader_b] = ParentOrSize::Parent(leader_a); self.parent_or_size[leader_a] = ParentOrSize::Size(merged_component_size); } // Decrease the number of connected components by one. self.group_num -= 1; // Return `true` because different connected components are newly combined. true } /// Return a list of connected components. /// /// Each connected component consists of indexes of nodes. /// The indexes of the nodes in each connected component are arranged in ascending order. /// The list of connected components is sorted in ascending order /// with respect to the smallest index of the included nodes. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(5); /// uf.merge(1, 2); /// uf.merge(2, 3); /// assert_eq!(uf.groups(), vec![vec![0], vec![1, 2, 3], vec![4]]); /// ``` pub fn groups(&mut self) -> Vec<Vec<usize>> { // Number of nodes in graph. let element_num = self.parent_or_size.len(); // List of connected components. let mut groups: Vec<Vec<usize>> = vec![]; // Correspondence between the representative node and group index. let mut leader_to_idx: Vec<Option<usize>> = vec![None; element_num]; // Assign each node in the graph to a group. for node in 0..element_num { // Representative node of the connected component to which the `node` belongs. let leader = self.leader(node); if let Some(group_idx) = leader_to_idx[leader] { // Assign to an existing group. groups[group_idx].push(node); } else { // Adding a new group. leader_to_idx[leader] = Some(groups.len()); groups.push(vec![node]); } } // Return a list of groups. groups } /// Return the number of nodes in the connected component to which node `a` belongs. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(3); /// assert_eq!(uf.size(0), 1); /// uf.merge(0, 1); /// assert_eq!(uf.size(0), 2); /// uf.merge(2, 1); /// assert_eq!(uf.size(0), 3); /// ``` pub fn size(&mut self, a: usize) -> usize { let leader = self.leader(a); match self.parent_or_size[leader] { ParentOrSize::Parent(_) => panic!(), ParentOrSize::Size(size) => size, } } /// Add a new node with degree `0`. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(4); /// uf.merge(1, 2); /// uf.merge(2, 3); /// assert_eq!(uf.groups(), vec![vec![0], vec![1, 2, 3]]); /// uf.add(); /// assert_eq!(uf.groups(), vec![vec![0], vec![1, 2, 3], vec![4]]); /// ``` pub fn add(&mut self) { self.parent_or_size.push(ParentOrSize::Size(1)); self.group_num += 1; } /// Return the number of connected components. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(3); /// assert_eq!(uf.group_num(), 3); /// uf.merge(0, 1); /// assert_eq!(uf.group_num(), 2); /// uf.merge(2, 1); /// assert_eq!(uf.group_num(), 1); /// ``` pub fn group_num(&self) -> usize { self.group_num } /// Return the number of nodes in the graph. /// /// # Examples /// /// ``` /// use atcoder8_library::union_find::UnionFind; /// /// let mut uf = UnionFind::new(5); /// assert_eq!(uf.elem_num(), 5); /// ``` pub fn elem_num(&self) -> usize { self.parent_or_size.len() } } }