ひとりで勝手にはじめた蟻本読書会 半分全列挙 全探索を高速化するテクニック 蟻本読書会 の続きです。

座標圧縮とは数列 A[0], A[0], …, A[N-1] が与えられたときに、それぞれの要素が全体の中で何番目に小さいかを求める処理のことです。値の大小関係を保ったまま小さな自然数に変換できます。

たとえば以下のような問題だと H, W の値が小さい場合は2次元配列をつかって幅優先探索で解く方法があります。マスキングテープで覆われていないセルで連続したものを選択しつづけることで領域の数を取得することができるわけです。ところが H, W の上限が 1,000,000 と大きいと2次元配列を宣言しようとしてもメモリーが足りません。このようなときに座標圧縮の処理をすることで問題を解くことができるようになります。

E – ペンキの色

E – ペンキの色

長方形のベニヤ板にペンキを塗り看板を制作したい。ベニヤ板には色を塗りたくないところにあらかじめ何枚かの長方形のマスキングテープ(図の灰色の部分)が貼られている。マスキングテープで区切られた領域ごとに別々の色を使いペンキを塗る。図なら 4 色のペンキを使う。

入力としてマスキングテープを貼る位置が与えられた時、使うペンキの色の数を求めるプログラムを作成せよ。ただしベニヤ板全体がマスキングテープで覆われることはなく、全てのマスキングテープの辺はベニヤ板のいずれかの辺に平行である。

入力されるデータ
W H
N
a_1 b_1 c_1 d_1
a_2 b_2 c_2 d_2

a_N b_N c_N d_N

(ただし、
W はベニヤ板の幅
H はベニヤ板の高さ
N はマスキングテープの数
a_i, b_i c_i d_i
i 番目に貼るマスキングテープの左下の座標 (a_i, b_i) と右上の座標 (c_i, d_i)

1 ≦ W, H ≦ 1,000,000
1 ≦ N ≦ 1000
0 ≦ a_i < c_i ≦ W
0 ≦ b_i < d_i ≦ H )

数列 A を座標圧縮をするときは A のなかの重複する値を削除したあと、昇順ソート(小さい順に並べ替える)します。そのあと先頭から取り出せばインデックスが座標圧縮後の値になっています。

C – Reorder Cards

C – Reorder Cards

H 行 W 列の格子状に H × W 枚のカードが並べられています。i = 1, …, N について、上から A_i 行目、左から B_i 列目にあるカードには数 i が書かれており、それ以外の H × W – N 枚のカードには何も書かれていません。

これらのカードに対し、以下の 2 種類の操作を可能な限り繰り返します。

数の書かれたカードを含まない行が存在するとき、その行のカードを全て取り除き、残りのカードを上へ詰める
数の書かれたカードを含まない列が存在するとき、その列のカードを全て取り除き、残りのカードを左へ詰める

操作が終了したとき、数が書かれたカードがそれぞれどこにあるか求めてください。

N 行出力せよ。操作終了後に数 i が書かれたカードが上から C_i 行目、左から D_i 列目に存在するとき、i 行目には C_i, D_i をこの順に空白区切りで出力せよ。

入力されるデータ
H W N
A_1 B_1
A_2 B_2
 …
A_N B_N

(ただし、1 ≦ H, W ≦ 10^9
1 ≦ N ≦ min(10^5, H × W)
1 ≦ A_i ≦ H, 1 ≦ B_i ≦ W )

座標圧縮のアルゴリズムを考えれば、座標圧縮によって取り除くべき行と列が取り除かれることに気づきます。

E – 魚の生息範囲 (Fish)

E – 魚の生息範囲 (Fish)

海の中に N 種類の魚がいる。それぞれの魚には直方体状の生息範囲が定まっている。魚は境界も含めて生息範囲の中のどの場所にも移動できるが、生息範囲の外に出ることは決してない。海の中の点は 3 つの実数 (x, y, d) によって表される。
(x, y, d) は 上空から見たときにある地点を基準にして東に x、北に y 進んだ位置であり、海面からの深さが d の点を表す。ただし海面は平面であるとする。

K 種類以上の魚の生息範囲が重なる場所がどのくらいあるかを知りたい。そのような場所全体の体積を求めるプログラムを作成せよ。

N K
a_1 b_1 c_1 d_1 e_1 f_1
a_2 b_2 c_2 d_2 e_2 f_2

a_N b_N c_N d_N e_N f_N

(ただし、1 ≦ K ≦ N ≦ 50
魚は N 種類であり、K 種類以上の魚の生息範囲が重なる場所の体積を求めたいことを表す。
魚 i は a_i ≦ X ≦ d_i, b_i ≦ Y ≦ e_i, c_i ≦ Z ≦ f_i をみたす XYZ 座標のなかにいる。
0 ≦ a_i < d_i ≦ 1,000,000
0 ≦ b_i < e_i ≦ 1,000,000
0 ≦ c_i < f_i ≦ 1,000,000 )

これも座標圧縮する問題です。3次元配列を定義して何種類の魚がいるのかを調べますが、最大で 1,000,000 だと配列用のメモリーが足りません。しかし座標圧縮をすることで使用するメモリーを減らすことができます。

辞書で座標圧縮する前の座標としたあとの座標を高速で求めることができるようにしています。