AtCoder ABC #131 F - Must Be Rectangular!
AtCoder Beginner Contest 131 - AtCoder
反省
UnionFind木使うとかどうやったら思いつくんですかね…。
解説
参考: AtCoder ABC 131 F - Must Be Rectangular! (600 点) - けんちょんの競プロ精進記録
fn solve(xys: &[(usize, usize)]) -> usize { let n = xys.len(); const MAX: usize = 110000; let uf = UnionFind::new(MAX * 2 + 1); let mut mx = vec![0; MAX * 2 + 1]; let mut my = vec![0; MAX * 2 + 1]; for &(x, y) in xys.iter() { uf.unite(x, y + MAX); } for i in 1..(MAX + 1) { mx[uf.root(i)] += 1; my[uf.root(i + MAX)] += 1; } let mut ans = 0; for i in 1..(MAX * 2 + 1) { ans += mx[i] * my[i]; } ans - n }
問題文にある操作が完了すると、長方形のグループがいくつか出来上がることになる。 長方形の横の格子点数と縦の格子点数を掛けて(つまり長方形の)元の点の数を引けば、その長方形を作成する際に追加された点の数がわかる。
それを全長方形グループについて行うということは<長方形の格子点数> - N
を計算することになり、これが最後のans - n
となっている。
後は長方形グループを探せばよい。座標(x, y)をxとy+MAXの無効グラフとしてUnionFind木に登録していくことでこれを構築することができる。
mx[i]
にはiをrootとする長方形グループに属するx座標の数、my[i]
には同様にy座標の数が格納されるためmx[i] * my[i]
で長方形に含まれる格子点の数が得られる。
なお、iをrootとする長方形グループがない場合はmx[i] * my[i]
は0となる。