模板:ST表
解决rmq问题,区间最值的离线做法,写法比线段树和树状数组更加简单
构造O(nlog(n));
查询O(1);
只要运用倍增思想
构造ST表O(nlog(n)):
1 void ST_init(int n){ 2 for (int i=1;i<=n;i++)dp[i][0]=a[i]; 3 int len=(int)(log((double)(n))/log(2.0)); 4 for (int j=1;j<=len;j++) 5 for (int i=1;i<=n;i++){ 6 dp[i][j]=Max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); 7 } 8 }
dp[i][j]:表示从a[i]开始的2^j个元素的目标值;
查询O(1):
1 int ST_query(int l,int r){ 2 int k=int (log((double)(r-l+1))/log(2.0)); 3 return Max(dp[l][k],dp[r-(1<<k)+1][k]); 4 }
查询区间(l,r)之间的最值:k为log2(区间长度);dp[l][k]与dp[r-(l<<k)+1][k]覆盖了整个区间,取两者较优值即可
完整代码:
1 #include<cmath> 2 #include<iostream> 3 #include<stdio.h> 4 #include<cstring> 5 using namespace std; 6 const int NUM=2e6; 7 //rmq离线做法ST 在线做法 线段树 树状数组 8 //ST O(nlog(n))构造 O(1)查询 9 int a[NUM],n,m,dp[NUM][20]; 10 //dp[I][J]表示从I位开始的2^j个数的最小/大值 11 inline int read() 12 { 13 int x=0,f=1;char ch=getchar(); 14 while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} 15 while (isdigit(ch)){x=x*10+ch-48;ch=getchar();} 16 return x*f; 17 } 18 int Max(int x,int y){ 19 return x<y?y:x; 20 } 21 void ST_init(int n){ 22 for (int i=1;i<=n;i++)dp[i][0]=a[i]; 23 int len=(int)(log((double)(n))/log(2.0)); 24 for (int j=1;j<=len;j++) 25 for (int i=1;i<=n;i++){ 26 dp[i][j]=Max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); 27 } 28 } 29 int ST_query(int l,int r){ 30 int k=int (log((double)(r-l+1))/log(2.0)); 31 return Max(dp[l][k],dp[r-(1<<k)+1][k]); 32 } 33 int main(){ 34 n=read();m=read(); 35 for (int i=1;i<=n;i++)a[i]=read(); 36 ST_init(n); 37 for (int i=1;i<=m;i++){ 38 int l=read();int r=read(); 39 printf("%d\n",ST_query(l,r)); 40 } 41 }
浙公网安备 33010602011771号