1. 程式人生 > >st表復習筆記

st表復習筆記

\n 線段樹 問題 ostream 常數 com using ++ 開始

st表,一種高效的區間最值查詢(RMQ)算法。本質其實是一個動態規劃。

其實吧,對於看過線性dp的人來說應該不難理解,只是處理有些麻煩。但是本土狗因為-1的問題居然改了許久...

技術分享圖片

用兩個2^i的區間把整個區段覆蓋,dp[i][j]表示區間最值,從i開始,向前2^j個數字。根據動態規劃的定義,把這個區間分割成兩個小區間,於是就有

dp[i][j]=max(dp[i][j-1],dp[i][i+(1<<j-1)]);(然而我在這裏處理區間的時候多減了一個1....)

一直分割下去,直到1。復雜度O(nlogn)。

於是查詢:

我們找到左右區間大小(y-x+1),把它log一下,再2的次方一下,就成了覆蓋區間的最大2^i次方的區間。同理,右區間也是。比較兩區間最值,就可以得出最值了。

code:

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100005;
int n,m,a[maxn],dp[maxn][25],l[maxn];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    l[0]=-1;
    for(int i=1;i<=n;++i)
    {
        dp[i][
0]=a[i]; l[i]=l[i>>1]+1; } for(int j=1;j<=25;++j) { for(int i=1;i+(1<<j)-1<=n;++i) { dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } for(int i=1;i<=m;i++) { int x,y; scanf("
%d%d",&x,&y); int s=l[y-x+1]; printf("%d\n",max(dp[x][s],dp[y-(1<<s)+1][s])); } return 0; }

類比線段樹:

優點:

1、碼量小

2、快(不用說了,線段樹常數大得呦...)

缺點:

1、只能靜態

2、只能最值

(完)

st表復習筆記