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