結果
問題 | No.1983 [Cherry 4th Tune C] 南の島のマーメイド |
ユーザー | koba-e964 |
提出日時 | 2023-06-13 00:15:37 |
言語 | Rust (1.77.0 + proconio) |
結果 |
AC
|
実行時間 | 293 ms / 4,000 ms |
コード長 | 6,755 bytes |
コンパイル時間 | 18,386 ms |
コンパイル使用メモリ | 399,968 KB |
実行使用メモリ | 106,824 KB |
最終ジャッジ日時 | 2024-06-11 23:44:07 |
合計ジャッジ時間 | 26,856 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
6,812 KB |
testcase_01 | AC | 1 ms
6,816 KB |
testcase_02 | AC | 1 ms
6,812 KB |
testcase_03 | AC | 1 ms
6,940 KB |
testcase_04 | AC | 1 ms
6,944 KB |
testcase_05 | AC | 1 ms
6,940 KB |
testcase_06 | AC | 1 ms
6,944 KB |
testcase_07 | AC | 1 ms
6,944 KB |
testcase_08 | AC | 4 ms
6,940 KB |
testcase_09 | AC | 6 ms
6,940 KB |
testcase_10 | AC | 9 ms
6,940 KB |
testcase_11 | AC | 9 ms
6,940 KB |
testcase_12 | AC | 5 ms
6,944 KB |
testcase_13 | AC | 125 ms
31,468 KB |
testcase_14 | AC | 161 ms
35,676 KB |
testcase_15 | AC | 191 ms
45,052 KB |
testcase_16 | AC | 65 ms
28,260 KB |
testcase_17 | AC | 164 ms
36,164 KB |
testcase_18 | AC | 187 ms
44,544 KB |
testcase_19 | AC | 250 ms
53,364 KB |
testcase_20 | AC | 177 ms
42,148 KB |
testcase_21 | AC | 202 ms
40,872 KB |
testcase_22 | AC | 221 ms
43,776 KB |
testcase_23 | AC | 275 ms
57,268 KB |
testcase_24 | AC | 279 ms
57,260 KB |
testcase_25 | AC | 293 ms
58,136 KB |
testcase_26 | AC | 271 ms
58,060 KB |
testcase_27 | AC | 282 ms
57,324 KB |
testcase_28 | AC | 276 ms
57,200 KB |
testcase_29 | AC | 257 ms
57,216 KB |
testcase_30 | AC | 284 ms
58,684 KB |
testcase_31 | AC | 264 ms
57,640 KB |
testcase_32 | AC | 269 ms
58,304 KB |
testcase_33 | AC | 1 ms
6,944 KB |
testcase_34 | AC | 58 ms
27,064 KB |
testcase_35 | AC | 132 ms
78,600 KB |
testcase_36 | AC | 113 ms
42,292 KB |
testcase_37 | AC | 1 ms
6,940 KB |
testcase_38 | AC | 31 ms
6,940 KB |
testcase_39 | AC | 183 ms
106,824 KB |
testcase_40 | AC | 126 ms
56,832 KB |
ソースコード
use std::io::{Write, BufWriter}; // https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8 macro_rules! input { ($($r:tt)*) => { let stdin = std::io::stdin(); let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock())); let mut next = move || -> String{ bytes.by_ref().map(|r|r.unwrap() as char) .skip_while(|c|c.is_whitespace()) .take_while(|c|!c.is_whitespace()) .collect() }; input_inner!{next, $($r)*} }; } macro_rules! input_inner { ($next:expr) => {}; ($next:expr,) => {}; ($next:expr, $var:ident : $t:tt $($r:tt)*) => { let $var = read_value!($next, $t); input_inner!{$next $($r)*} }; } macro_rules! read_value { ($next:expr, ( $($t:tt),* )) => { ($(read_value!($next, $t)),*) }; ($next:expr, [ $t:tt ; $len:expr ]) => { (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>() }; ($next:expr, usize1) => (read_value!($next, usize) - 1); ($next:expr, $t:ty) => ($next().parse::<$t>().expect("Parse error")); } // Verified by: https://codeforces.com/contest/700/submission/165850980 // This function uses O(n) stack space. mod tecomp { use std::cmp::min; const INF: usize = 1 << 28; fn dfs<EIdx: Copy + PartialEq>(v: usize, paridx: EIdx, g: &[Vec<(usize, EIdx)>], ord: &mut [usize], low: &mut [usize], k: &mut usize, bridges: &mut Vec<EIdx>) { ord[v] = *k; low[v] = *k; *k += 1; for &(w, eidx) in g[v].iter() { if paridx == eidx { continue; } if ord[w] < ord[v] { low[v] = min(low[v], ord[w]); } else if ord[w] == INF { dfs(w, eidx, g, ord, low, k, bridges); low[v] = min(low[v], low[w]); if ord[v] < low[w] { bridges.push(eidx); } } } } fn dfs_comp<EIdx: Copy>( v: usize, g: &[Vec<(usize, EIdx)>], ord: &[usize], low: &[usize], cur_becomp: usize, becomp_count: &mut usize, becomp: &mut [usize], tree: &mut [Vec<(usize, EIdx)>], vis: &mut [bool], ) { becomp[v] = cur_becomp; vis[v] = true; for &(w, eidx) in g[v].iter() { if ord[w] > ord[v] && !vis[w] { if ord[v] < low[w] { *becomp_count += 1; tree[cur_becomp].push((*becomp_count, eidx)); dfs_comp(w, g, ord, low, *becomp_count, becomp_count, becomp, tree, vis); } else { dfs_comp(w, g, ord, low, cur_becomp, becomp_count, becomp, tree, vis); } } } } type EIdx = usize; // Returns (the number of 2-edge connected components, [the id of the component v belongs to | v <- [0 .. g.len()]], the resulting tree, the ids of bridges). // Graphs are given and provided in the adjacent list format. (to, edge_id). // The provided tree has its own vertex ids, but edge ids are reused. // This function uses O(n) stack space. pub fn decomp(g: &[Vec<(usize, EIdx)>]) -> (usize, Vec<usize>, Vec<Vec<(usize, EIdx)>>, Vec<EIdx>) { let n_vert = g.len(); let mut ord = vec![INF; n_vert]; let mut low = vec![INF; n_vert]; let mut k = 0; let mut becomp_count = 0; let mut becomp = vec![INF; n_vert]; let mut bridges = Vec::new(); // rooted forest let mut tree = vec![Vec::new(); n_vert]; let mut vis = vec![false; n_vert]; for i in 0 .. n_vert { if !vis[i] { dfs(i, !0, &g, &mut ord, &mut low, &mut k, &mut bridges); dfs_comp(i, &g, &ord, &low, becomp_count, &mut becomp_count, &mut becomp, &mut tree, &mut vis); becomp_count += 1; } } tree = tree[..becomp_count].to_vec(); (becomp_count, becomp, tree, bridges) } } // mod tecomp // Union-Find tree. // Verified by https://atcoder.jp/contests/pakencamp-2019-day3/submissions/9253305 struct UnionFind { disj: Vec<usize>, rank: Vec<usize> } impl UnionFind { fn new(n: usize) -> Self { let disj = (0..n).collect(); UnionFind { disj: disj, rank: vec![1; n] } } fn root(&mut self, x: usize) -> usize { if x != self.disj[x] { let par = self.disj[x]; let r = self.root(par); self.disj[x] = r; } self.disj[x] } fn unite(&mut self, x: usize, y: usize) { let mut x = self.root(x); let mut y = self.root(y); if x == y { return } if self.rank[x] > self.rank[y] { std::mem::swap(&mut x, &mut y); } self.disj[x] = y; self.rank[y] += self.rank[x]; } #[allow(unused)] fn is_same_set(&mut self, x: usize, y: usize) -> bool { self.root(x) == self.root(y) } #[allow(unused)] fn size(&mut self, x: usize) -> usize { let x = self.root(x); self.rank[x] } } fn main() { // In order to avoid potential stack overflow, spawn a new thread. let stack_size = 104_857_600; // 100 MB let thd = std::thread::Builder::new().stack_size(stack_size); thd.spawn(|| solve()).unwrap().join().unwrap(); } // https://yukicoder.me/problems/no/1983 (3.5) // 関節点と橋を求め、橋だけで関節点・次数 1 の頂点すべてを繋いだときに同じ連結成分に属しているかどうか。 // パスが一意 => 構成する辺は全て橋: 橋以外が含まれているとそれを除去した時連結なので別のパスが取れる。 // パスが一意 => 通過する頂点はすべて関節点 or 次数 1: => そうでないとそれを除去した時、連結なままなので別のパスが取れる。 // 橋の両端は関節点 or 次数 1 であるため、後者の条件はいらないはず。 fn solve() { let out = std::io::stdout(); let mut out = BufWriter::new(out.lock()); macro_rules! puts {($($format:tt)*) => (let _ = write!(out,$($format)*););} input! { n: usize, m: usize, q: usize, uv: [(usize1, usize1); m], xy: [(usize1, usize1); q], } let mut uf = UnionFind::new(n); let mut g = vec![vec![]; n]; for i in 0..m { let (u, v) = uv[i]; g[u].push((v, i)); g[v].push((u, i)); } let (_, _, _, bridges) = tecomp::decomp(&g); for &idx in &bridges { let (u, v) = uv[idx]; uf.unite(u, v); } for (x, y) in xy { puts!("{}\n", if uf.is_same_set(x, y) { "Yes" } else { "No" }); } }