Skip to content

Commit df63a42

Browse files
committed
🥺chore
1 parent ae007e8 commit df63a42

File tree

2 files changed

+99
-76
lines changed

2 files changed

+99
-76
lines changed

practice2/k/main.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,23 @@ def make_list(n, *args, default=0): return [make_list(*args, default=default) fo
3838

3939
# モノイドに対して適用可能、Nが2冪でなくても良い
4040
class LazySegTree():
41+
'''
42+
Affine変換の際の各関数の例
43+
44+
monoid_identity = 0
45+
operator_identity = (1,0)
46+
47+
def monoid_func(x,y):
48+
return (x+y) % MOD
49+
def composition(a,b):
50+
b0,c0 = a
51+
b1,c1 = b
52+
return ((b0*b1) % MOD,(b1*c0+c1) % MOD)
53+
def effect(x,a,r):
54+
b,c = a
55+
return (b*x+c*r) % MOD
56+
'''
57+
4158
def __init__(self, initial_values, monoid_func, composition, effect, monoid_identity, operator_identity):
4259
self.N = len(initial_values)
4360
self.monoid_func = monoid_func

snipetts/lazy_segment_tree.py

Lines changed: 82 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,102 @@
1-
# still buggy
2-
# https://tjkendev.github.io/procon-library/python/range_query/rmq_ruq_segment_tree_lp.html
3-
class LazySegmentTree:
4-
# N: 処理する区間の長さ
5-
# 0-indexed, if N == 10 => [0 ~ 9]
6-
# min version
7-
# seg = LazySegmentTree(N, f=min, default=float("inf"))
8-
def __init__(self, N, f=lambda x,y: x+y, default=0):
9-
self.N = N
10-
self.default = default
11-
self.f = f
121

13-
self.LV = (N-1).bit_length()
14-
self.N0 = 2**self.LV
15-
self.data = [self.default]*(2*self.N0)
16-
self.lazy = [None]*(2*self.N0)
2+
# モノイドに対して適用可能、Nが2冪でなくても良い
3+
class LazySegTree():
4+
'''
5+
Affine変換の際の各関数の例
176
18-
# 伝搬対象の区間を求める
19-
def gindex(self, l, r):
20-
L = (l + self.N0) >> 1
21-
R = (r + self.N0) >> 1
22-
lc = 0 if l & 1 else (L & -L).bit_length()
23-
rc = 0 if r & 1 else (R & -R).bit_length()
24-
for i in range(self.LV):
25-
if rc <= i: yield R
26-
if L < R and lc <= i: yield L
27-
L >>= 1
28-
R >>= 1
7+
monoid_identity = 0
8+
operator_identity = (1,0)
299
30-
# 遅延伝搬処理
31-
def propagates(self, *ids):
32-
for i in reversed(ids):
33-
v = self.lazy[i-1]
34-
if v is None: continue
35-
self.lazy[2*i-1] = self.data[2*i-1] = self.lazy[2*i] = self.data[2*i] = v
36-
self.lazy[i-1] = None
10+
def monoid_func(x,y):
11+
return (x+y) % MOD
12+
def composition(a,b):
13+
b0,c0 = a
14+
b1,c1 = b
15+
return ((b0*b1) % MOD,(b1*c0+c1) % MOD)
16+
def effect(x,a,r):
17+
b,c = a
18+
return (b*x+c*r) % MOD
19+
'''
3720

38-
# 区間[l, r)をxで更新
39-
def update(self, x, l, r=None):
40-
if r is None: r = l + 1
21+
def __init__(self, initial_values, monoid_func, composition, effect, monoid_identity, operator_identity):
22+
self.N = len(initial_values)
23+
self.monoid_func = monoid_func
24+
self.composition = composition # composition(f, g) => g(f(x))の順であることに注意
25+
self.effect = effect #右作用 effect(a, f) => f(a), 雑に可換な処理を書こうとするとバグるので注意
26+
self.monoid_identity = monoid_identity
27+
self.operator_identity = operator_identity
28+
self.data = [self.monoid_identity]*(2*self.N)
29+
self.lazy = [self.operator_identity]*(2*self.N)
30+
self.size = [0]*(2*self.N)
4131

42-
*ids, = self.gindex(l, r)
43-
self.propagates(*ids)
32+
for i, ai in enumerate(initial_values):
33+
self.data[self.N+i] = ai
34+
self.size[self.N+i] = 1
35+
for i in range(self.N-1,0,-1):
36+
self.data[i] = self.monoid_func(self.data[i << 1], self.data[i << 1 | 1])
37+
self.size[i] = self.size[i << 1] + self.size[i << 1 | 1]
4438

45-
L, R = self.N0 + l, self.N0 + r
46-
while L < R:
47-
if R & 1:
48-
R -= 1
49-
self.lazy[R-1] = self.data[R-1] = x
50-
if L & 1:
51-
self.lazy[L-1] = self.data[L-1] = x
52-
L += 1
53-
L >>= 1
54-
R >>= 1
55-
for i in ids:
56-
self.data[i-1] = self.f(self.data[2*i-1], self.data[2*i])
39+
def update(self,i,x): # i番目(0-index)の値をxに変更
40+
i += self.N
41+
self.data[i] = x
42+
while i>1:
43+
i >>= 1
44+
self.data[i] = self.monoid_func(self.data[i << 1], self.data[i << 1 | 1])
45+
46+
def eval_at(self,i): # i番目で作用を施した値を返す
47+
return self.effect(self.data[i],self.lazy[i],self.size[i])
5748

58-
# 区間演算: [l, r)にxでfを作用させる
59-
def affect(self, x, l, r=None):
60-
if r is None: r = l + 1
49+
def eval_above(self,i): # i番目より上の値を再計算する
50+
while i > 1:
51+
i >>= 1
52+
self.data[i] = self.monoid_func(self.eval_at(i << 1),self.eval_at(i << 1 | 1))
6153

62-
*ids, = self.gindex(l, r)
63-
self.propagates(*ids)
54+
def propagate_at(self,i): # i番目で作用を施し、1つ下に作用の情報を伝える
55+
self.data[i] = self.effect(self.data[i],self.lazy[i],self.size[i])
56+
self.lazy[i << 1] = self.composition(self.lazy[i << 1],self.lazy[i])
57+
self.lazy[i << 1 | 1] = self.composition(self.lazy[i << 1 | 1], self.lazy[i])
58+
self.lazy[i] = self.operator_identity
6459

65-
L, R = self.N0 + l, self.N0 + r
60+
def propagate_above(self,i): # i番目より上で作用を施す
61+
H = i.bit_length()
62+
for h in range(H,0,-1):
63+
self.propagate_at(i >> h)
64+
65+
def fold(self, L, R): # [L,R)の区間取得
66+
L += self.N
67+
R += self.N
68+
L0 = L // (L & -L)
69+
R0 = R // (R & -R) - 1
70+
self.propagate_above(L0)
71+
self.propagate_above(R0)
72+
vL = self.monoid_identity
73+
vR = self.monoid_identity
6674
while L < R:
67-
if R & 1:
68-
R -= 1
69-
self.lazy[R-1] = self.f(self.data[R-1], x)
70-
self.data[R-1] = self.f(self.data[R-1], x)
7175
if L & 1:
72-
self.lazy[L-1] = self.f(self.data[L-1], x)
73-
self.data[L-1] = self.f(self.data[L-1], x)
76+
vL = self.monoid_func(vL,self.eval_at(L))
7477
L += 1
78+
if R & 1:
79+
R -= 1
80+
vR = self.monoid_func(self.eval_at(R),vR)
7581
L >>= 1
7682
R >>= 1
77-
for i in ids:
78-
self.data[i-1] = self.f(self.data[2*i-1], self.data[2*i])
83+
return self.monoid_func(vL,vR)
7984

80-
# 区間[l, r)内の最小値を求める
81-
def query(self, l, r=None):
82-
if r is None: r = l + 1
83-
self.propagates(*self.gindex(l, r))
84-
L, R = self.N0 + l, self.N0 + r
85-
86-
s = self.default
85+
def apply_range(self,L,R,x):
86+
L += self.N
87+
R += self.N
88+
L0 = L // (L & -L)
89+
R0 = R // (R & -R) - 1
90+
self.propagate_above(L0)
91+
self.propagate_above(R0)
8792
while L < R:
88-
if R & 1:
89-
R -= 1
90-
s = self.f(s, self.data[R-1])
9193
if L & 1:
92-
s = self.f(s, self.data[L-1])
94+
self.lazy[L] = self.composition(self.lazy[L], x)
9395
L += 1
96+
if R & 1:
97+
R -= 1
98+
self.lazy[R] = self.composition(self.lazy[R], x)
9499
L >>= 1
95100
R >>= 1
96-
return s
101+
self.eval_above(L0)
102+
self.eval_above(R0)

0 commit comments

Comments
 (0)