ST表算法詳解(算是吧)
ST表就是一個用來解決rmq(區間最值)問題的算法。
ST表不支持在線修改。
預處理時間複雜度O(nlogn),查詢時間O(1)。
ST表算法詳解(求最小值):
用mn[i][j]表示從j到j+2^i-1的最小值(長度顯然爲2^i)。
任意一段的最小值顯然等於min(前半段最小值,後半段最小值)。
那麼mn[i][j]如何用其餘狀態來繼承呢?
j到j+2^i-1的長度爲2^i,那麼一半的長度就等於2^(i-1)。
那麼前半段的狀態表示爲mn[i-1][j]。
後半段的長度也爲2^(i-1),起始位置爲j+2^(i-1)。
那麼後半段的狀態表示爲mn[i-1][j+2^(i-1)]。
因此:
mn[i][j]=min(mn[i-1][j],mn[i-1][j+2^(i-1)]。
算法
代碼實現:markdown
bin[0]=1; for(int i=1;i<20;i++) bin[i]=bin[i-1]*2;//bin[i]表示2的i次方 Log[0]=-1; for(int i=1;i<=200000;i++) Log[i]=Log[i/2]+1;//Log[i]表示log(i) for(int i=1;i<=n;i++) mn[0][i]=a[i];//顯然i到i+2^0-1就i一個位置,那麼最小值等於本身自己的值 for(int i=1;i<=Log[n];i++) for(int j=1;j<=n;j++) if(j+bin[i]-1<=n) mn[i][j]=min(mn[i-1][j],mn[i-1][j+bin[i-1]]);//狀態繼承
搞定了初始化以後,剩下的就是來查詢了。
首先明白一個定理:
2^log(a)>a/2
這個很簡單,由於log(a)表示小於等於a的2的最大幾回方。
好比說log(4)=2,log(5)=2,log(6)=2,log(7)=2,log(8)=3,log(9)=3…….
那麼咱們要查詢x到y的最小值。
設len=y-x+1,t=log(len)
根據上面的定理:2^t>len/2
從位置上來講,x+2^t越過了x到y的中間!
由於位置過了一半
因此x到y的最小值能夠表示爲min(從x日後2^t的最小值,從y往前2^t的最小值)
前面的狀態表示爲mn[t][x]
設後面(從y往前2^t的最小值)的初始位置是k,
那麼k+2^t-1=y,因此k=y-2^t+1
因此後面的狀態表示爲mn[t][y-2^t+1]
因此x到y的最小值表示爲min(mn[t][x],mn[t][y-2^t+1]),因此查詢時間複雜度是O(1)
spa
代碼實現:code
int t=Log[y-x+1]; printf("%d\n",min(mn[t][x],mn[t][y-bin[t]+1]));
ST表到這裏大概就講完了。
總結的來講求rmq問題有多種方法:線段樹,ST表(表示蒟蒻只學了這兩種)….
線段樹預處理O(nlogn),查詢O(logn),支持在線修改
ST表預處理O(nlogn),查詢O(1),但不支持在線修改
要根據題目給出的時限和問題來調整解法,但願對同窗們有所幫助吧(蒟蒻奉上)
繼承