AVL木を実装してみるの続きです。

一直線状に並んだ区間の集合は、AVL木を用いることで、効率的に管理することができます。

E – Cover query

E – Cover query

問題の趣旨は以下のとおりです。

Q 回にわたって L と R が与えられるので L 番目のマスから R 番目までのマスを黒く塗る。
そのあと黒く塗られているマスの数を出力せよ。

半開区間 [left, right) をAVL木に格納して新しい半開区間が格納されようとしたときに既存の半開区間とマージできるならマージする処理を繰り返すことで解を得ることができます。

新しい半開区間 [left, right) と既存の半開区間 [old_left, old_right) がまったく重なっていないのであればそのまま追加し、一部または全部が重なっているのであれば既存の半開区間は取り除いて新しい区間の left と right の値を調整して追加することで区間をマージする処理をおこないます。

既存の半開区間から left ≦ old_left である最小のものを探します。みつかったら old_left が right 以下であるか調べます。もしそうなら削除し、新しく追加しようとしている半開区間の left と right を left = min(left, old_left), right = max(right, old_right) と更新し、もう一度この処理を繰り返します。そうでない場合や要素そのものが見つからない場合は処理を終了します。

次に既存の半開区間から old_left ≦ right である最大のものを探します。みつかったら old_right が left 以上であるか調べます。もしそうなら削除し、新しく追加しようとしている半開区間の left と right を left = min(left, old_left), right = max(right, old_right) と更新し、もう一度この処理を繰り返します。そうでない場合や要素そのものが見つからない場合は処理を終了します。

削除すべき既存の半開区間を削除したら新しい半開区間を追加します。削除された区間の長さと新たに追加された区間の長さの差分をみれば解を得ることができます。

E – 1D Bucket Tool

E – 1D Bucket Tool

問題の趣旨は以下のとおりです。

クエリタイプ 1 では指定されたマスと繋がっている同じ色のマスをすべて指定された色に塗り直す。
クエリタイプ 2 では指定された色のマスの個数を出力する。

上の問題と似ていますが、マージしてよいのは接している同じ色の区間だけです。なので区間の色も記録する必要があります。

LRクラスを以下のように定義します。今回は Length をフィールド変数にするのではなく、L と R を変更したときに区間の長さが自動的に再計算されるようにプロパティとして定義します。

半開区間の色が変わったらその前後にある区間の色を調べます。同じ色であればマージします。半開区間は left の値で管理しているので、マージするときは ① nextをcurにマージさせる、② curをprevにマージさせるという順番でやったほうがわかりやすいです。