セグメント木メニューのサムネイル
(問題 3)Segment Treeの構築3: Segment Treeの構築 Objective-C編(paizaランク A 相当)

問題にチャレンジして、ユーザー同士で解答を教え合ったり、コードを公開してみよう!

問題

下記の問題をプログラミングしてみよう!

(はじめに)

いよいよ、問題 2 で扱った完全二分木のノードにデータを載せて、演算を高速に処理していきます。

今回は行いたい処理は長さ n = 5 の配列 A = [1,5,7,9,8] に対し、区間maxを計算することを考えていきます。

ここで区間maxとはある範囲における最大値を指します。例えば A の 0 番目から 2 番目までの区間maxは max(1, 5, 7) = 7 となります。

完全二分木に載せるためには葉の数が配列の長さ以上ある必要があります。根と葉の距離を k としたときに、葉の数は 2 ** k となります。そのため、2 ** k ≧ n を満たす必要があります。

また k が大きくなりすぎると、木も大きくなりすぎてしまうためここでは、k は n - 1 のビット長とします。ここでは、0 のビット長は 0 とします。また、葉の数を N = 2 ** k とします。このとき頂点数は 2 × N - 1 とします。

まず、わかりやすくするため完全二分木の各頂点について番号を振っていきます。いろいろな振り方がありますが、実装上以下のルールにのっとって番号を振っていきます。

根を頂点番号 0 とし、頂点 i の左の子が頂点 2 × i + 1, 右の子が頂点 2 × i + 2 となるように番号を振っていきます。

今回、番号を振り終えたものが下の木になります。赤い数字が頂点番号です。



ここからは、データを載せていくことを考えます。

まず、葉に配列 A のデータを載せます。左の葉から順に、つまり、頂点 N - 1 から順に A の配列の要素を載せていきます。

ここで、葉が余ってしまいました。そのときにはダミーのデータを載せることを考えます。ダミーのデータとして、ダミーではないデータとの計算ではそのデータに影響を及ばさないようにしなければいけません。今回後に取り組む問題では、0 ≦ A_i ≦ 10 ^ 9 なので、任意の A_i において max(0, A_i) = A_i となりその他のデータには影響を及ぼさない事がわかります。そのため今回は 0 をダミーのデータとして使います。このようなものを単位元と言います。(詳細は問題 4)

ここまでのをまとめたのが下の木になります。黄色の数字がその頂点に載せたデータです。



最後に葉以外の頂点にもデータを載せていきます。

葉以外の頂点については、2 つの子についてmax演算を行った結果を載せます。具体的には、頂点 i には、max((頂点番号 2 × i + 1 のデータ),(頂点番号 2 × i + 2 のデータ)) を載せます。このとき、計算順序としては、子の要素が確定していなければいけないので、葉に近い順、つまり、番号が大きいほうから計算していけばよいです。

ここまでのをまとめたのが下の木になり、これでSegment Treeの構築が終わりました。



木の状態で管理するのは難しいため、実装では配列 (以降 Tree とする) で管理することとします。Tree の長さは完全二分木の頂点数とし、Tree の i 番目の要素は頂点 i に載せたデータを入れればよいです。この例では Tree = [9,9,8,5,9,8,0,1,5,7,9,8,0,0,0] となります。

では、以下の問題ではこの方法でSegment Treeを構築してみましょう。

(問題)

長さ n の配列 A が与えられます。上記の方法で求まる Tree を出力してください。ただし、ダミーのデータは 0 としてください。

入力される値

入力は以下のフォーマットで与えられます。


n
A_0 A_1 ... A_{n - 1}


1 行目には 1 つの整数 n が与えられます。

2 行目には n つの整数 A_0,A_1,...,A_{n - 1} が与えられます。

入力は合計 2 行からなり、入力値最終行の末尾に改行を 1 つ含みます。


入力値最終行の末尾に改行が1つ入ります。
文字列は標準入力から渡されます。 標準入力からの値取得方法はこちらをご確認ください
期待する出力

答えを 2 行で出力してください。

1 行目には配列 Tree の長さを、2 行目には配列 Tree の各要素を空白区切りで出力してください。

条件

すべてのテストケースについて以下の条件を満たします。

  • 1 ≦ n ≦ 200000

  • 0 ≦ A_i ≦ 10^9 (0 ≦ i ≦ n - 1)
  • 入力例1

    5
    1 5 7 9 8

    出力例1

    15
    9 9 8 5 9 8 0 1 5 7 9 8 0 0 0

    入力例2

    1
    100

    出力例2

    1
    100

    問題一覧へ戻る

    1. paizaラーニングトップ
    2. レベルアップ問題集
    3. セグメント木メニュー(言語選択)
    4. 問題一覧 Objective-C編
    5. (問題 3)Segment Treeの構築3: Segment Treeの構築 Objective-C編
    ページの先頭へ戻る