結果

問題 No.878 Range High-Element Query
ユーザー yukimyyukimy
提出日時 2024-06-10 19:04:19
言語 Crystal
(1.11.2)
結果
AC  
実行時間 586 ms / 2,000 ms
コード長 3,118 bytes
コンパイル時間 16,484 ms
コンパイル使用メモリ 298,072 KB
実行使用メモリ 16,640 KB
最終ジャッジ日時 2024-06-10 19:04:42
合計ジャッジ時間 23,315 ms
ジャッジサーバーID
(参考情報)
judge2 / judge5
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
5,248 KB
testcase_01 AC 3 ms
5,248 KB
testcase_02 AC 4 ms
5,376 KB
testcase_03 AC 4 ms
5,376 KB
testcase_04 AC 3 ms
5,376 KB
testcase_05 AC 3 ms
5,376 KB
testcase_06 AC 2 ms
5,376 KB
testcase_07 AC 2 ms
5,376 KB
testcase_08 AC 4 ms
5,376 KB
testcase_09 AC 4 ms
5,376 KB
testcase_10 AC 2 ms
5,376 KB
testcase_11 AC 452 ms
14,976 KB
testcase_12 AC 465 ms
12,288 KB
testcase_13 AC 367 ms
10,856 KB
testcase_14 AC 274 ms
9,984 KB
testcase_15 AC 440 ms
13,952 KB
testcase_16 AC 550 ms
13,652 KB
testcase_17 AC 567 ms
16,640 KB
testcase_18 AC 586 ms
14,080 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

class SegmentTree(T)
  @sz : Int64
  #配列、単位元、比較用の演算をブロックで渡す
  def initialize(ary : Array(T), @defv : T, &block : T, T -> T)
    n = ary.size.to_i64
    sz = 1_i64
    while sz < n
      sz *= 2
    end
    @tree = Array(T).new(sz*2-1,@defv)
    @sz = sz
    @compare_proc = block
    i = 0
    #葉に元の値を入れる
    while i < n
      @tree[i+sz-1] = ary[i]
      i += 1
    end
    i = sz - 2
    while i >= 0
      #親に上って子を比較しながら値を入れる
      @tree[i] = @compare_proc.call(@tree[i*2+1], @tree[i*2+2])
      i -= 1
    end
  end

  #全ての葉を返す
  def tree
    @tree[@sz-1..-1]
  end

  #indexを指定して値を返す
  def [] (i : Int64)
    i += @sz - 1
    @tree[i]
  end

  #数値による置換
  def update(i : Int64, val : T)
    i += @sz - 1
    #葉を更新する
    @tree[i] = val
    while i > 0
      i = (i-1) // 2
      #親に上って更新する
      @tree[i] = @compare_proc.call(@tree[i*2+1], @tree[i*2+2])
    end
  end

  #ブロックによる置換
  def update(i : Int64)
    i += @sz - 1
    #葉を更新する
    @tree[i] = yield(@tree[i])
    while i > 0
      i = (i-1) // 2
      #親に上って更新する
      @tree[i] = @compare_proc.call(@tree[i*2+1], @tree[i*2+2])
    end
  end

  #特定区間の演算結果を返す
  def get(a : Int64, b : Int64, now = 0_i64, l = 0_i64, r = -1_i64)
    r = @sz if r < 0
    return @defv if (b <= l || r <= a)
    return @tree[now] if (a <= l && r <= b)
    vl = get(a,b,now*2+1,l,(l+r)//2)
    vr = get(a,b,now*2+2,(l+r)//2,r)
    return @compare_proc.call(vl, vr)
  end    
end

#Binary Indexed Tree
#0~iの区間和を求める
#区間加算対応
class BIT
  def initialize(size : Int64)
    #1-indexにする
    @size = size + 1
    @bit = Array(Array(Int64)).new(2) {Array(Int64).new(@size,0_i64)}
  end
  
  #半開区間
  def add(l : Int64, r : Int64, x : Int64)
    l += 1
    r += 1
    add_sub(0,l,-x*(l-1))
    add_sub(0,r,x*(r-1))
    add_sub(1,l,x)
    add_sub(1,r,-x)
  end

  def get(i)
    i += 1
    return get_sub(0,i) + get_sub(1,i) * i
  end

  #l以上r以下(閉区間)
  def get(l : Int64, r : Int64)
    get(r) - get(l-1)
  end

  def add_sub(p, i : Int64, x : Int64)
    while i < @size
      @bit[p][i] += x
      i += (i & -i)
    end
  end
    
  def get_sub(p, i : Int64)
    res = 0_i64
    while i > 0
      res += @bit[p][i]
      i -= (i & -i)
    end
    return res
  end
end

n, q = read_line.split.map(&.to_i64)
a = read_line.split.map(&.to_i64)
query = Array(Tuple(Int64, Int64, Int64)).new
q.times do |i|
  _, l, r = read_line.split.map(&.to_i64)
  query << {r - 1, l - 1, i}
end
query.sort!
tree1 = SegmentTree(Int64).new(a, 0_i64) { |a, b| a > b ? a : b }
tree2 = BIT.new(n) 
k = 0_i64
ans = Array.new(q, 0_i64)
a.each_with_index do |v, i|
  i = i.to_i64
  l = (0_i64..i).bsearch do |j|
    tree1.get(j, i + 1) <= v
  end
  tree2.add(l.not_nil!, i + 1, 1_i64)
  while k < q && query[k][0] == i
    ans[query[k][2]] = tree2.get(query[k][1], query[k][1])
    k += 1
  end
end
puts ans.join("\n")
0