https://atcoder.jp/contests/abc392/tasks/abc392_e
Union-Findを使ってグラフを連結していきますが、連結に寄与しない、すなわちrootが同じになるエッジをためておいてあとで連結に使います。
// Cables and Servers #![allow(non_snake_case)] use std::collections::HashSet; //////////////////// library //////////////////// fn read<T: std::str::FromStr>() -> T { let mut line = String::new(); std::io::stdin().read_line(&mut line).ok(); line.trim().parse().ok().unwrap() } fn read_vec<T: std::str::FromStr>() -> Vec<T> { read::<String>().split_whitespace() .map(|e| e.parse().ok().unwrap()).collect() } //////////////////// Graph //////////////////// type Node = usize; type Edge = (Node, Node); fn read_edge() -> Edge { let v: Vec<Node> = read_vec(); let (A, B) = (v[0] - 1, v[1] - 1); (A, B) } //////////////////// UnionFind //////////////////// use std::cmp::max; struct UnionFind { parents: Vec<Node>, heights: Vec<i32>, } impl UnionFind { fn new(N: usize) -> UnionFind { let parents: Vec<Node> = (0..N).collect(); let heights: Vec<i32> = vec![1; N]; UnionFind { parents, heights } } fn is_root(&self, v: Node) -> bool { self.parents[v] == v } fn connect(&mut self, u: Node, v: Node) { let r1 = self.root(u); let r2 = self.root(v); if r1 == r2 { return } let h1 = self.heights[r1]; let h2 = self.heights[r2]; if h1 <= h2 { // r2にr1がぶら下がる self.parents[r1] = r2; self.heights[r2] = max(self.heights[r2], self.heights[r1]+1); } else { self.parents[r2] = r1; self.heights[r1] = max(self.heights[r1], self.heights[r2]+1); } } fn root(&self, v0: Node) -> Node { if self.is_root(v0) { v0 } else { let p = self.parents[v0]; self.root(p) } } } //////////////////// process //////////////////// fn read_input() -> (usize, Vec<Edge>) { let v: Vec<usize> = read_vec(); let (N, M) = (v[0], v[1]); let edges: Vec<Edge> = (0..M).map(|_| read_edge()).collect(); (N, edges) } fn F(N: usize, edges: Vec<Edge>) { let mut tree = UnionFind::new(N); let mut extra_edges: Vec<(usize, Edge)> = vec![]; for (i, edge) in edges.into_iter().enumerate() { let (A, B) = edge; let r1 = tree.root(A); let r2 = tree.root(B); if r1 == r2 { extra_edges.push((i, edge)) } else { tree.connect(r1, r2) } } let mut set_roots: HashSet<Node> = (0..N).filter(|&v| tree.is_root(v)). collect(); let L = set_roots.len(); println!("{}", L-1); for &(k, (A, _)) in &extra_edges[..L-1] { let r1 = tree.root(A); let &r2 = set_roots.iter().filter(|&&r| r != r1).next().unwrap(); tree.connect(r1, r2); if tree.root(r2) == r2 { set_roots.remove(&r1); } else { set_roots.remove(&r2); } println!("{} {} {}", k+1, A+1, r2+1) } } fn main() { let (N, edges) = read_input(); F(N, edges) }