f[i][j] 表示 以i号点为起点 的长度为 2^j 次方 终点为i+2^j-1 的最大或者最小值
打表时间复杂度 O(Nlog2(N)) 查询O(1)
打表代码:
for(int i=1;i<=n;i++) { scanf("%d",&f[i][0]); } for(int j=1;j<=log2(n);j++) { for(int i=1;i+(1<<j)-1<=n;i++) { f[i][j]=max(f[i][(j-1)],f[i+(1<<j-1)][j-1]); } }
将区间分为两段 [i ,i+2^(j-1)-1 ] 和[2^(j-1)+i,i+2^j-1]
查询代码:
scanf("%d%d",&l,&r); int k=log2(r-l+1); printf("%d ",max(f[l][k],f[r-(1<<k)+1][k]));
k 为区间长度的log2 值 查询 l到l+2^k-1 和r-(2^k)+1 到 r
关于二维 RMQ
查询一个矩阵里面的最大最小值
例题 POJ https://vjudge.net/problem/POJ-2019
code:
// #include<iostream> #include<cstdio> #include<cmath> using namespace std; int f1[260][260][40],f2[260][260][40]; int n,b,kk; int RMQ(int x,int y,int c) { int k=log2(c); int xx=x+c-1; int yy=y+c-1; int i=x,j=y; int t1=min(f2[i][j][k],f2[xx-(1<<k)+1][j][k]); t1=min(t1,min(f2[xx-(1<<k)+1][yy-(1<<k)+1][k],f2[i][yy-(1<<k)+1][k])); int t2=max(f1[xx-(1<<k)+1][yy-(1<<k)+1][k],f1[i][yy-(1<<k)+1][k]); t2=max(max(f1[i][j][k],f1[xx-(1<<k)+1][j][k]),t2); return t2-t1; } int main() { scanf("%d%d%d",&n,&b,&kk); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&f1[i][j][0]); f2[i][j][0]=f1[i][j][0]; } for(int k=1;k<=log2(n);k++) { for(int i=1;i+(1<<k)-1<=n;i++) for(int j=1;j+(1<<k)-1<=n;j++) { int t1=min(f2[i][j][k-1],f2[i+(1<<k-1)][j][k-1]); int t2=min(f2[i][j+(1<<k-1)][k-1],f2[i+(1<<k-1)][j+(1<<k-1)][k-1]); f2[i][j][k]=min(t1,t2); t1=max(f1[i][j][k-1],f1[i+(1<<k-1)][j][k-1]); t2=max(f1[i][j+(1<<k-1)][k-1],f1[i+(1<<k-1)][j+(1<<k-1)][k-1]); f1[i][j][k]=max(t1,t2); } } int x,y; while(kk--) { scanf("%d%d",&x,&y); printf("%d ",RMQ(x,y,b)); } }