1. 程式人生 > 實用技巧 >洛谷P3865 -【模板】ST表 - RMQ模板題 - ST演算法

洛谷P3865 -【模板】ST表 - RMQ模板題 - ST演算法

題目連結

https://www.luogu.com.cn/problem/P3865

適用範圍

主要是處理區間最值問題。

時間複雜度

\(O(n\log_{}{n})\)的時間內進行預處理,\(O(1)\)的時間進行查詢。(線段樹解決可能會超時)

\(j\)即列數:最大是$\log_{2}{n} $(計算機上預設以log以2為底),

也就是如果以一個表格形式呈現的話,那麼行數為\(n\),列數為$ \log_{2}{n} $。

本題的f陣列列數開17就行,因為\(\log_{2}{1e5} \approx 16.6\)

演算法分析

ST演算法是線上處理RMQ的演算法,是一個DP思想,但是狀態轉移方程是從前面已知的一列轉移過來,和揹包有所不同。

主要思想就是:分治、倍增、動規。

\(f[i,j]\)陣列表示的是:從第\(i\)個數起連續\(2^j\)個數中的最大值。(個數包括第\(i\)個數)

學習連結

https://www.bilibili.com/video/BV1pE411u7Gq?from=search&seid=10536624648902837005

注意

本題scanf輸入會有一組資料TLE,所以建議快讀。

AC程式碼

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+20;

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}

int f[N][21];    

int main()
{
    int n=read(),m=read(); // 序列長度 詢問次數
    for(int i=1;i<=n;i++)
    {
        f[i][0]=read(); // 初始化f陣列,畫一個圖可以得出這個結論
    }
    int x=(int)(log(n)/log(2));
    for(int j=1;j<=x;j++)
    {
        int w=n-(1<<j)+1;
        for(int i=1;i<=w;i++)
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    }
    for(int i=1;i<=m;i++)
    {
        int l=read(),r=read();
        int w=(int)(log(r-l+1)/log(2));
        printf("%d\n",max(f[l][w],f[r-(1<<w)+1][w])); // 別忘了+1
    }
    return 0;
}