[python刷题模板] ZKW线段树
一、 算法&数据结构
1. 描述
zkw比普通线段树常数低,采用了非递归写法,空间和时间上都要优势。
注意模板是0-indexed。
- 待补充
2. 复杂度分析
- 查询query, O(log2n)
- 更新update,O(log2n)
3. 常见应用
4. 常用优化
二、 模板代码
1.单点更新,区间询问最大值(PUIQ)
例题: cf1691e
用线段树维护前缀和的最大值
class ZKW:
# n = 1
# size = 1
# log = 2
# d = [0]
# op = None
# e = 10 ** 15
"""自低向上非递归写法线段树,0_indexed
tmx = ZKW(pre, max, -2 ** 61)
"""
__slots__ = ('n', 'op', 'e', 'log', 'size', 'd')
def __init__(self, V, OP, E):
"""
V: 原数组
OP: 操作:max,min,sum
E: 每个元素默认值
"""
self.n = len(V)
self.op = OP
self.e = E
self.log = (self.n - 1).bit_length()
self.size = 1 << self.log
self.d = [E for i in range(2 * self.size)]
for i in range(self.n):
self.d[self.size + i] = V[i]
for i in range(self.size - 1, 0, -1):
self.update(i)
def set(self, p, x):
# assert 0 <= p and p < self.n
update = self.update
p += self.size
self.d[p] = x
for i in range(1, self.log + 1):
update(p >> i)
def get(self, p):
# assert 0 <= p and p < self.n
return self.d[p + self.size]
def query(self, l, r): # [l,r)左闭右开
# assert 0 <= l and l <= r and r <= self.n
sml, smr, op, d = self.e, self.e, self.op, self.d
l += self.size
r += self.size
while l < r:
if l & 1:
sml = op(sml, d[l])
l += 1
if r & 1:
smr = op(d[r - 1], smr)
r -= 1
l >>= 1
r >>= 1
return self.op(sml, smr)
def all_query(self):
return self.d[1]
def max_right(self, l, f):
"""返回l右侧第一个不满足f的位置"""
# assert 0 <= l and l <= self.n
# assert f(self.e)
if l == self.n:
return self.n
l += self.size
sm, op, d, size = self.e, self.op, self.d, self.size
while True:
while l % 2 == 0:
l >>= 1
if not (f(op(sm, d[l]))):
while l < size:
l = 2 * l
if f(op(sm, d[l])):
sm = op(sm, d[l])
l += 1
return l - size
sm = op(sm, d[l])
l += 1
if (l & -l) == l:
break
return self.n
def min_left(self, r, f):
"""返回r左侧连续满足f的最远位置的位置"""
# assert 0 <= r and r < self.n
# assert f(self.e)
if r == 0:
return 0
r += self.size
sm, op, d, size = self.e, self.op, self.d, self.size
while True:
r -= 1
while r > 1 and (r % 2):
r >>= 1
if not (f(op(d[r], sm))):
while r < size:
r = (2 * r + 1)
if f(op(d[r], sm)):
sm = op(d[r], sm)
r -= 1
return r + 1 - size
sm = op(d[r], sm)
if (r & -r) == r:
break
return 0
def update(self, k):
self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])
def __str__(self):
return str([self.get(i) for i in range(self.n)])