Skip to content

Commit e1b53ec

Browse files
author
robot
committed
feat: segment tree
1 parent a950fd3 commit e1b53ec

File tree

1 file changed

+134
-67
lines changed

1 file changed

+134
-67
lines changed

src/codeTemplates/segmentTree.js

Lines changed: 134 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -121,73 +121,73 @@ export default {
121121
{
122122
language: "py",
123123
text: `
124-
class LazySegmentTree:
125-
def __init__(self, data):
126-
'''
127-
data:传入的数组
128-
'''
129-
self.data = data
130-
self.n = len(data)
131-
# 申请4倍data长度的空间来存线段树节点
132-
self.tree = [0] * (4 * self.n) # 索引i的左孩子索引为2i+1,右孩子为2i+2
133-
# 要点 1 开始
134-
self.dirty = [True] * (4 * self.n) # 索引i的左孩子索引为2i+1,右孩子为2i+2
135-
# 要点 1 结束
136-
if self.n:
137-
self.build(0, 0, self.n-1)
138-
139-
def build(self, tree_index, l, r):
140-
if l == r:
141-
self.tree[tree_index] = self.data[l]
142-
return
143-
left, right = 2 * tree_index + 1, 2 * tree_index + 2
144-
mid = (l + r) // 2
145-
self.build(left, l, mid)
146-
self.build(right, mid+1, r)
147-
self.tree[tree_index] = self.tree[left] + self.tree[right]
148-
149-
def updateSum(self, ql, qr):
150-
self.update(0, 0, self.n-1, ql, qr)
151-
152-
def update(self, tree_index, l, r, ql, qr):
153-
if l == ql and r == qr:
154-
# 要点 2 开始
155-
self.dirty[tree_index] = not self.dirty[tree_index]
156-
self.tree[tree_index] = r - l + 1 - self.tree[tree_index]
157-
# 要点 2 结束
158-
return
159-
left, right = 2 * tree_index + 1, 2 * tree_index + 2
160-
mid = (l + r) // 2
161-
# 要点 3 开始
162-
if not self.dirty[tree_index]: # 如果有标记就处理
163-
self.update(left, l, mid, l, mid)
164-
self.update(right, mid+1, r, mid+1, r)
165-
self.dirty[tree_index] = True # 重置回去
166-
# 要点 3 结束
167-
if qr <= mid: self.update(left, l, mid, ql, qr)
168-
elif ql > mid: self.update(right, mid+1, r, ql, qr)
169-
else:
170-
self.update(left, l, mid, ql, mid)
171-
self.update(right, mid+1, r, mid+1, qr)
172-
self.tree[tree_index] = self.tree[left] + self.tree[right]
173-
174-
def querySum(self, ql, qr):
175-
return self.query(0, 0, self.n-1, ql, qr)
176-
177-
def query(self, tree_index, l, r, ql, qr):
178-
if l == ql and r == qr:
179-
return self.tree[tree_index]
180-
left, right = 2 * tree_index + 1, 2 * tree_index + 2
181-
mid = (l + r) // 2
182-
# 要点 3 开始
183-
if not self.dirty[tree_index]: # 如果有标记就处理
184-
self.update(left, l, mid, l, mid)
185-
self.update(right, mid+1, r, mid+1, r)
186-
self.dirty[tree_index] = True # 重置回去
187-
# 要点 3 结束
188-
if qr <= mid: return self.query(left, l, mid, ql, qr)
189-
if ql > mid: return self.query(right, mid+1, r, ql, qr)
190-
return self.query(left, l, mid, ql, mid) + self.query(right, mid+1, r, mid+1, qr)
124+
class LazySegmentTree:
125+
def __init__(self, data):
126+
'''
127+
data:传入的数组
128+
'''
129+
self.data = data
130+
self.n = len(data)
131+
# 申请4倍data长度的空间来存线段树节点
132+
self.tree = [0] * (4 * self.n) # 索引i的左孩子索引为2i+1,右孩子为2i+2
133+
# 要点 1 开始
134+
self.dirty = [True] * (4 * self.n) # 索引i的左孩子索引为2i+1,右孩子为2i+2
135+
# 要点 1 结束
136+
if self.n:
137+
self.build(0, 0, self.n-1)
138+
139+
def build(self, tree_index, l, r):
140+
if l == r:
141+
self.tree[tree_index] = self.data[l]
142+
return
143+
left, right = 2 * tree_index + 1, 2 * tree_index + 2
144+
mid = (l + r) // 2
145+
self.build(left, l, mid)
146+
self.build(right, mid+1, r)
147+
self.tree[tree_index] = self.tree[left] + self.tree[right]
148+
149+
def updateSum(self, ql, qr, val):
150+
self.update(0, 0, self.n-1, ql, qr, val)
151+
152+
def update(self, tree_index, l, r, ql, qr, val):
153+
if l == ql and r == qr:
154+
# 要点 2 开始
155+
self.dirty[tree_index] = not self.dirty[tree_index]
156+
self.tree[tree_index] = (r - l + 1) * val
157+
# 要点 2 结束
158+
return
159+
left, right = 2 * tree_index + 1, 2 * tree_index + 2
160+
mid = (l + r) // 2
161+
# 要点 3 开始
162+
if not self.dirty[tree_index]: # 如果有标记就处理
163+
self.update(left, l, mid, l, mid, val)
164+
self.update(right, mid+1, r, mid+1, r, val)
165+
self.dirty[tree_index] = True # 重置回去
166+
# 要点 3 结束
167+
if qr <= mid: self.update(left, l, mid, ql, qr, val)
168+
elif ql > mid: self.update(right, mid+1, r, ql, qr, val)
169+
else:
170+
self.update(left, l, mid, ql, mid, val)
171+
self.update(right, mid+1, r, mid+1, qr, val)
172+
self.tree[tree_index] = self.tree[left] + self.tree[right]
173+
174+
def querySum(self, ql, qr):
175+
return self.query(0, 0, self.n-1, ql, qr)
176+
177+
def query(self, tree_index, l, r, ql, qr):
178+
if l == ql and r == qr:
179+
return self.tree[tree_index]
180+
left, right = 2 * tree_index + 1, 2 * tree_index + 2
181+
mid = (l + r) // 2
182+
# 要点 3 开始
183+
if not self.dirty[tree_index]: # 如果有标记就处理
184+
self.update(left, l, mid, l, mid)
185+
self.update(right, mid+1, r, mid+1, r)
186+
self.dirty[tree_index] = True # 重置回去
187+
# 要点 3 结束
188+
if qr <= mid: return self.query(left, l, mid, ql, qr)
189+
if ql > mid: return self.query(right, mid+1, r, ql, qr)
190+
return self.query(left, l, mid, ql, mid) + self.query(right, mid+1, r, mid+1, qr)
191191
`
192192
}
193193
]
@@ -260,5 +260,72 @@ class SegmentTree:
260260
},
261261
],
262262
},
263+
{
264+
text: '动态开点',
265+
problems: [{
266+
id: 'maximum-sum-queries',
267+
title: '2736. 最大和查询'
268+
}],
269+
codes: [{
270+
language: 'py',
271+
text: `
272+
class Node:
273+
def __init__(self, l, r):
274+
self.left = None # 左孩子的指针
275+
self.right = None # 右孩子的指针
276+
self.l = l # 区间左端点
277+
self.r = r # 区间右端点
278+
self.m = (l + r) >> 1 # 中点
279+
self.v = 0 # 当前值
280+
self.add = 0 # 懒标记
281+
282+
class SegmentTree:
283+
def __init__(self,n):
284+
# 默认就一个根节点,不 build 出整个树,节省空间
285+
self.root = Node(0,n-1) # 根节点
286+
287+
def update(self, l, r, v, node):
288+
if l > node.r or r < node.l:
289+
return
290+
if l <= node.l and node.r <= r:
291+
node.v = (node.r - node.l + 1) * v
292+
node.add = v # 做了一个标记
293+
return
294+
self.__pushdown(node) # 动态开点。为子节点赋值,这个值就从 add 传递过来
295+
self.update(l, r, v, node.left)
296+
self.update(l, r, v, node.right)
297+
self.__pushup(node) # 动态开点结束后,修复当前节点的值
298+
299+
def query(self, l, r,node):
300+
if l > node.r or r < node.l:
301+
return 0
302+
if l <= node.l and node.r <= r:
303+
return node.v
304+
self.__pushdown(node) # 动态开点。为子节点赋值,这个值就从 add 传递过来
305+
return self.query(l, r, node.left) + self.query(l, r, node.right)
306+
307+
def __pushdown(self,node):
308+
if node.left is None:
309+
node.left = Node(node.l, node.m)
310+
if node.right is None:
311+
node.right = Node(node.m + 1, node.r)
312+
if node.add > 0:
313+
node.left.v = (node.left.r - node.left.l + 1) * node.add
314+
node.right.v = (node.right.r - node.right.l + 1) * node.add
315+
node.left.add = node.add
316+
node.right.add = node.add
317+
node.add = 0
318+
319+
def __pushup(self,node):
320+
node.v = node.left.v + node.right.v
321+
322+
def updateSum(self,index,val):
323+
self.update(index,index,val,self.root)
324+
325+
def querySum(self,left,right):
326+
return self.query(left,right,self.root)
327+
`
328+
}]
329+
}
263330
],
264331
};

0 commit comments

Comments
 (0)