ST表
https://www.luogu.com.cn/problem/P3865
首先预处理出 l o g 2 n 的整数值,用 i > > 1 优化 i ÷ 2 的过程。 首先预处理出log_2n的整数值, 用i >> 1优化i\div2的过程。 首先预处理出log2n的整数值,用i>>1优化i÷2的过程。
def pre_lg():
# 预处理出log2n的整数值
lg[1] = 0
lg[2] = 1
for i in range(3, n + 1):
lg[i] = lg[i >> 1] + 1
F [ i , j ] 表示数列 A 中下标在子区间 [ i , i + 2 j − 1 ] 里的数的最大值。 ( 1 < < i 表示 2 i ) F[i, j] 表示数列A中下标在子区间[i, i+2^j-1]里的数的最大值。 \\ (1 << i 表示2^i) F[i,j]表示数列A中下标在子区间[i,i+2j−1]里的数的最大值。(1<<i表示2i)
def ST_prework():
for i in range(1, n + 1): # 区间[i, i] 的最大值显然为a[i]
f[i][0] = a[i]
j = 1
while 1 << j <= n: # 枚举以i为起点长度j的子区间
for i in range(1, n - (1 << j) + 1 + 1):
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1])
# 即长度为1 << j 的子区间的最大值是左右两半长度为 1 << (j - 1)中最大的那个
j += 1
def ST_query(l, r):
k = lg[r - l + 1]
return max(f[l][k], f[r - (1 << k) + 1][k])
找到一个 k ,满足 2 k ≤ r − l + 1 ≤ 2 k + 1 , 这样才能覆盖 [ l , r ] 整个区间。 ( [ l , r ] 区间长度为 r − l + 1 ) 找到一个k,满足2^k\leq r- l + 1\leq 2^{k + 1},这样才能覆盖[l, r]整个区间。 \\([l, r]区间长度为r-l+1) 找到一个k,满足2k≤r−l+1≤2k+1,这样才能覆盖[l,r]整个区间。([l,r]区间长度为r−l+1)
eg:
完整代码
import sys
input = lambda: sys.stdin.readline().rstrip("\r\n")
printf = lambda d: sys.stdout.write(str(d) + "\n")
def read():
line = sys.stdin.readline().strip()
while not line:
line = sys.stdin.readline().strip()
return map(int, line.split())
def pre_lg():
# 预处理出log2n的整数值
lg[1] = 0
lg[2] = 1
for i in range(3, n + 1):
lg[i] = lg[i >> 1] + 1
def ST_prework():
for i in range(1, n + 1): # 区间[i, i] 的最大值显然为a[i]
f[i][0] = a[i]
j = 1
while 1 << j <= n: # 枚举以i为起点长度j的子区间
for i in range(1, n - (1 << j) + 1 + 1):
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1])
# 即长度为1 << j 的子区间的最大值是左右两半长度为 1 << (j - 1)中最大的那个
j += 1
def ST_query(l, r):
k = lg[r - l + 1]
return max(f[l][k], f[r - (1 << k) + 1][k])
n, m = read()
a = list(read())
a = [0] + a
lg = [0] * (n + 1)
pre_lg()
f = [[0] * (lg[n] + 2) for _ in range(n + 1)]
ST_prework()
for _ in range(m):
l, r = read()
printf(ST_query(l, r))