Skip to content

Commit 17d319c

Browse files
committed
🥺chore
1 parent 27c3a73 commit 17d319c

File tree

2 files changed

+130
-2
lines changed

2 files changed

+130
-2
lines changed

practice2/l/main.py

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,136 @@ def make_list(n, *args, default=0): return [make_list(*args, default=default) fo
3636

3737
sys.setrecursionlimit(1000000)
3838

39+
40+
# モノイドに対して適用可能、Nが2冪でなくても良い
41+
class LazySegmentTree():
42+
'''
43+
Affine変換(x <- bx + c)の際の各関数の例
44+
45+
monoid_identity = 0
46+
operator_identity = (1,0)
47+
48+
def monoid_func(x,y):
49+
return (x+y) % MOD
50+
def composition(f,g): #g(f(x))の順に作用する
51+
b0,c0 = f
52+
b1,c1 = g
53+
return ((b0*b1) % MOD,(b1*c0+c1) % MOD)
54+
def effect(x,f,r): #xは格納されているデータ(モノイド)
55+
b,c = f
56+
return (b*x+c*r) % MOD
57+
'''
58+
59+
def __init__(self, initial_values, monoid_func, composition, effect, monoid_identity, operator_identity):
60+
self.N = len(initial_values)
61+
self.monoid_func = monoid_func
62+
self.composition = composition # composition(f, g) => g(f(x))の順であることに注意
63+
self.effect = effect #右作用 effect(a, f) => f(a), 雑に可換な処理を書こうとするとバグるので注意
64+
self.monoid_identity = monoid_identity
65+
self.operator_identity = operator_identity
66+
self.data = [self.monoid_identity]*(2*self.N)
67+
self.lazy = [self.operator_identity]*(2*self.N)
68+
self.size = [0]*(2*self.N)
69+
70+
for i, ai in enumerate(initial_values):
71+
self.data[self.N+i] = ai
72+
self.size[self.N+i] = 1
73+
for i in range(self.N-1,0,-1):
74+
self.data[i] = self.monoid_func(self.data[i << 1], self.data[i << 1 | 1])
75+
self.size[i] = self.size[i << 1] + self.size[i << 1 | 1]
76+
77+
def update(self,i,x): # i番目(0-index)の値をxに変更
78+
i += self.N
79+
self.data[i] = x
80+
while i>1:
81+
i >>= 1
82+
self.data[i] = self.monoid_func(self.data[i << 1], self.data[i << 1 | 1])
83+
84+
def eval_at(self,i): # i番目で作用を施した値を返す
85+
return self.effect(self.data[i],self.lazy[i],self.size[i])
86+
87+
def eval_above(self,i): # i番目より上の値を再計算する
88+
while i > 1:
89+
i >>= 1
90+
self.data[i] = self.monoid_func(self.eval_at(i << 1),self.eval_at(i << 1 | 1))
91+
92+
def propagate_at(self,i): # i番目で作用を施し、1つ下に作用の情報を伝える
93+
self.data[i] = self.effect(self.data[i],self.lazy[i],self.size[i])
94+
self.lazy[i << 1] = self.composition(self.lazy[i << 1],self.lazy[i])
95+
self.lazy[i << 1 | 1] = self.composition(self.lazy[i << 1 | 1], self.lazy[i])
96+
self.lazy[i] = self.operator_identity
97+
98+
def propagate_above(self,i): # i番目より上で作用を施す
99+
H = i.bit_length()
100+
for h in range(H,0,-1):
101+
self.propagate_at(i >> h)
102+
103+
def fold(self, L, R): # [L,R)の区間取得
104+
L += self.N
105+
R += self.N
106+
L0 = L // (L & -L)
107+
R0 = R // (R & -R) - 1
108+
self.propagate_above(L0)
109+
self.propagate_above(R0)
110+
vL = self.monoid_identity
111+
vR = self.monoid_identity
112+
while L < R:
113+
if L & 1:
114+
vL = self.monoid_func(vL,self.eval_at(L))
115+
L += 1
116+
if R & 1:
117+
R -= 1
118+
vR = self.monoid_func(self.eval_at(R),vR)
119+
L >>= 1
120+
R >>= 1
121+
return self.monoid_func(vL,vR)
122+
123+
def apply_range(self,L,R,x):# 区間 [L,R) にxを作用
124+
L += self.N
125+
R += self.N
126+
L0 = L // (L & -L)
127+
R0 = R // (R & -R) - 1
128+
self.propagate_above(L0)
129+
self.propagate_above(R0)
130+
while L < R:
131+
if L & 1:
132+
self.lazy[L] = self.composition(self.lazy[L], x)
133+
L += 1
134+
if R & 1:
135+
R -= 1
136+
self.lazy[R] = self.composition(self.lazy[R], x)
137+
L >>= 1
138+
R >>= 1
139+
self.eval_above(L0)
140+
self.eval_above(R0)
141+
39142
def main():
40-
N = I()
143+
N, Q = LI()
144+
A = LI()
145+
X = [(1-a, a, 0) for a in A]
146+
query = LIR(Q)
147+
148+
monoid_identity = (0, 0, 0)
149+
operator_identity = 0
150+
151+
def monoid_func(x,y):
152+
return (x[0] + y[0], x[1] + y[1], x[2] + y[2] + x[1] * y[0])
153+
154+
def composition(f, g):
155+
return f ^ g
156+
157+
def effect(x, f, r):
158+
c0, c1, cnt = x
159+
return (c1, c0, c0 * c1 - cnt) if f else x
160+
161+
seg = LazySegmentTree(X, monoid_func, composition, effect, monoid_identity, operator_identity)
162+
163+
for t, l, r in query:
164+
if t == 1:
165+
seg.apply_range(l-1, r, 1)
166+
else:
167+
print(seg.fold(l-1, r)[-1])
168+
41169

42170
if __name__ == '__main__':
43171
main()

snipetts/lazy_segment_tree.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
# モノイドに対して適用可能、Nが2冪でなくても良い
3-
class LazySegTree():
3+
class LazySegmentTree():
44
'''
55
Affine変換の際の各関数の例
66

0 commit comments

Comments
 (0)