洛谷P3865 -【模板】ST表 - RMQ模板題 - ST演算法
阿新 • • 發佈:2020-09-11
題目連結
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; }