ST算法求区间最值

【概念】

通过o(nlogn)的预处理将询问区间最值过程优化到o(1) 。关键是他的代码很短,你也可以用他来写区间和。唯一的缺点就是无法即使更改。如果需要更改数值,那么你去用线段树吧。

【预处理数组】

我们以求最大值为例,其他的最小值,区间和,都是类似。

a为数据数组。

定义数组f[i][j]代表从i开始,连续2^j个数的最大值。那么对于f[i][j],我们可以拆成2^(j – 1)的两端推出f[i][j],分别是从ii + 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;
posted @ 2010-10-29 16:35  Sephiroth.L.  阅读(488)  评论(0编辑  收藏  举报