結果
| 問題 |
No.876 Range Compress Query
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2024-06-10 17:09:34 |
| 言語 | Crystal (1.14.0) |
| 結果 |
AC
|
| 実行時間 | 418 ms / 2,000 ms |
| コード長 | 3,142 bytes |
| コンパイル時間 | 16,319 ms |
| コンパイル使用メモリ | 311,368 KB |
| 実行使用メモリ | 26,336 KB |
| 最終ジャッジ日時 | 2025-01-02 10:50:11 |
| 合計ジャッジ時間 | 20,036 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 18 |
ソースコード
#遅延評価セグ木
class LazySegmentTree(T)
@sz : Int64
#配列、単位元、単位元関数、二項演算、作用関数、作用合成関数をブロックで渡す
def initialize(ary : Array(T), @e : Proc(T), @id : Proc(Act), @operator : T, T -> T, @mapping : Act, T -> T, @composition : Act, Act -> Act)
@n = ary.size.to_i64
sz = 1_i64
while sz < @n
sz *= 2
end
@tree = Array(T).new(sz*2-1,@e.call)
@lazy = Array(Act).new(sz*2-1,@id.call)
@sz = sz
i = 0_i64
#葉に元の値を入れる
while i < sz
if i >= @n
@tree[i+sz-1] = @e.call
else
@tree[i+sz-1] = ary[i]
end
i += 1
end
i = sz - 2
while i >= 0
#親に上って子を比較しながら値を入れる
@tree[i] = @operator.call(@tree[i*2+1], @tree[i*2+2])
i -= 1
end
end
def tree
i = 0_i64
while i < @sz - 1
eval(i)
i += 1
end
res = Array(Int64).new
while i < @sz + @n - 1
eval(i)
res << @tree[i].val
i += 1
end
return res
end
#indexを指定して返す
def [] (i : Int64)
get(i,i+1)
end
def eval(i : Int64)
return if @lazy[i] == @id.call
if i < @sz - 1
#子に合成
@lazy[i*2+1] = @composition.call(@lazy[i], @lazy[i*2+1])
@lazy[i*2+2] = @composition.call(@lazy[i], @lazy[i*2+2])
end
#適用
@tree[i] = @mapping.call(@lazy[i], @tree[i])
#単位元関数に戻す
@lazy[i] = @id.call
end
def update(a : Int64, b : Int64, f : Act, now = 0_i64, l = 0_i64, r = -1_i64)
r = @sz if r < 0
eval(now)
return if (r <= a || b <= l)
if a <= l && r <= b
@lazy[now] = f
eval(now)
elsif (a < r && l < b)
update(a,b,f,now*2+1,l,(l+r)//2)
update(a,b,f,now*2+2,(l+r)//2,r)
@tree[now] = @operator.call(@tree[now*2+1],@tree[now*2+2])
end
end
def get(a : Int64, b : Int64, now = 0_i64, l = 0_i64, r = -1_i64)
eval(now)
r = @sz if r < 0
return @e.call if (r <= a || b <= l)
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 @operator.call(vl, vr)
end
end
#以下を事前に設定
record Node, l : Int64, r : Int64, v : Int64
record Act, x : Int64
op = -> (x : Node, y : Node) do
if x.l == -1
y
elsif y.l == -1
x
else
Node.new(x.l, y.r, x.v + y.v + (x.r == y.l ? 0 : 1))
end
end
e = -> () { Node.new(-1_i64, -1_i64, 0_i64) }
mapping = -> (f : Act, x : Node) { Node.new(x.l + f.x, x.r + f.x, x.v) }
id = -> () { Act.new(0_i64) } # 引数が有意な関数と一致しないよう注意
composition = -> (g : Act, f : Act) { Act.new(g.x + f.x) } # g(f(x))になるように
n, q = read_line.split.map(&.to_i64)
a = read_line.split.map(&.to_i64)
ary = a.map { |v| Node.new(v, v, 0_i64) }
tree = LazySegmentTree(Node).new(ary, e, id, op, mapping, composition)
q.times do
query = read_line.split.map(&.to_i64)
t = query[0]
l = query[1]
r = query[2]
if t == 1
tree.update(l - 1, r, Act.new(query[3]))
else
puts tree.get(l - 1, r).v + 1
end
end