這道題能夠用ST表過:
記錄4個數組:maxval[][], minval[][], ans[][], rans[][]
maxval[i][j]表示從i號元素開始,長度爲(1<<j)(也就是2^j)的區間上的最大值
minval[i][j]表示從i號元素開始,長度爲(1<<j)的區間上的最小值
ans[i][j]表示從i號元素開始,長度爲(1<<j)的區間從左往右方向的答案
rans[i][j]表示從i號元素開始,長度爲(1<<j)的區間從右往左方向的答案
那麼易得以下轉移方程:
maxval[i][j] = max(maxval[i][j - 1], maxval[i + (1 << (j - 1))][j - 1])
minval差很少
對於ans和rans的轉移,咱們這樣考慮
區間[l, r]上的答案,要麼是區間[l, (l+r)/2]上的答案,要麼是區間[(l+r)/2+1, r]上的答案,要麼是[(l+r)/2+1, r]上的最大值減去[l, (l+r)/2]上的最小值,以上三者中取最大者
ans[i][j] = max(ans[i][j - 1], ans[i + (1 << (j - 1))][j - 1], maxval[i + (1 << (j - 1))][j - 1] - minval[i][j - 1]);
rans差很少
在預處理的時候,要把j的循環提到外層,由於[l, r]的狀態須要用到[(l+r)/2+1, r]的狀態轉移而來
若是j的循環在內層的話,求解[l, r]的狀態時[(l+r)/2+1, r]的狀態尚未求解過
查詢的過程應該比較好理解,直接看代碼吧
#include <algorithm>
#include <cmath>
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::max;
using std::min;
template <typename T>
inline const T &max(const T &a, const T &b, const T &c)
{
return max(a, max(b, c));
}
const double LOG2 = std::log(2);
int a[200010];
int maxval[200010][50];
int minval[200010][50];
int ans[200010][50];
int rans[200010][50];
int n, m;
inline void stInit()
{
for (int i = 1; i <= n; ++i)
minval[i][0] = maxval[i][0] = a[i];
for (int j = 1; 1 << j <= n; ++j)
for (int i = 1; i + (1 << j) - 1 <= n; ++i)
{
minval[i][j] = min(minval[i][j - 1], minval[i + (1 << (j - 1))][j - 1]);
maxval[i][j] = max(maxval[i][j - 1], maxval[i + (1 << (j - 1))][j - 1]);
ans[i][j] = max(ans[i][j - 1], ans[i + (1 << (j - 1))][j - 1],
maxval[i + (1 << (j - 1))][j - 1] - minval[i][j - 1]);
rans[i][j] = max(rans[i][j - 1], rans[i + (1 << (j - 1))][j - 1],
maxval[i][j - 1] - minval[i + (1 << (j - 1))][j - 1]);
}
}
inline int queryMax(int l, int r)
{
int k = static_cast<int>(std::log(r - l + 1) / LOG2);
return max(maxval[l][k], maxval[r - (1 << k) + 1][k]);
}
inline int queryMin(int l, int r)
{
int k = static_cast<int>(std::log(r - l + 1) / LOG2);
return min(minval[l][k], minval[r - (1 << k) + 1][k]);
}
inline int queryAns(int l, int r)
{
int k = static_cast<int>(std::log(r - l + 1) / LOG2);
if (l + (1 << k) > r)
return max(ans[l][k], ans[r - (1 << k) + 1][k]);
else
return max(ans[l][k], ans[r - (1 << k) + 1][k],
queryMax(l + (1 << k), r) - queryMin(l, r - (1 << k)));
}
inline int queryRans(int l, int r)
{
int k = static_cast<int>(std::log(r - l + 1) / LOG2);
if (l + (1 << k) > r)
return max(rans[l][k], rans[r - (1 << k) + 1][k]);
else
return max(rans[l][k], rans[r - (1 << k) + 1][k],
queryMax(l, r - (1 << k)) - queryMin(l + (1 << k), r));
}
int main()
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
stInit();
cin >> m;
while (m--)
{
int l, r;
cin >> l >> r;
if (l < r)
cout << queryAns(l, r) << endl;
else if (l > r)
cout << queryRans(r, l) << endl;
else
cout << 0 << endl;
}
return 0;
}
不難看出,查詢的時間複雜度是O(1)的,預處理的時間複雜度是O(nlogn)的