ST算法求区间最值
【概念】
通过o(nlogn)的预处理将询问区间最值过程优化到o(1) 。关键是他的代码很短,你也可以用他来写区间和。唯一的缺点就是无法即使更改。如果需要更改数值,那么你去用线段树吧。
【预处理数组】
我们以求最大值为例,其他的最小值,区间和,都是类似。
设a为数据数组。
定义数组f[i][j]代表从i开始,连续2^j个数的最大值。那么对于f[i][j],我们可以拆成2^(j – 1)的两端推出f[i][j],分别是从i到i + 2^(j – 1) – 1和从i + 2^(j – 1)到i + 2^j。即:
f[i][j] = max(f[i][j – 1],f[i + (1 << (j – 1))][j – 1]); (1 << j = 2^j)
【询问】
很神奇的过程,利用了一些数学关系。当询问区间[l,r]时,进行的操作如下:
k = (int)(ln(r – l +1) / ln(2));
ans = max(f[l][k],f[r - 2^k + 1][k]);
即将[l,r]分成恰好能用预处理数组表达的两端。
【总结】
ST算法是和树状数组类似,利用2的次方进行数据预处理,从而达到优化的方法。很有用处,推荐理解记忆。
【代码】
pascal版:
function find(l,r:longint):longint;//数组的预处理 begin if (f[l][r] > 0) then exit(f[l][r]); if (r = 0) then f[l][r] := a[l] else f[l][r] := max(find(l,r - 1),find(l + (1 shl (r – 1)),r - 1)); exit(f[l][r]); end; function make(l,r:longint):longint;.//询问从l到r的最大值 var k:longint; begin k := (longint)(ln(r - l + 1) / ln(2)); exit(max(find(l,k),find(r - (1 shl k) + 1,k))); end;