RMQ (Range Minimum/Maximum Query)问题

时间:2021-08-15 16:04:55
**************************************************************************************************************

一维RMQ查找最大值下标模板
一维RMQ模版
二维RMQ模板

**************************************************************************************************************
①一维RMQ查找最大值下标模板
int n,q;
int val[N];
int mx[20][N];
int tlog[N];
int p[21];

void make_maxrmq() {
   int i,j,k;
   for(i=1;i<=n;i++) mx[0][i]=i;
   for(j=1;p[j]<=n;j++)
      for(i=1;i+p[j]-1<=n;i++) {
         if(val[ mx[j-1][i] ]>val[ mx[j-1][i+p[j-1]] ])
            mx[j][i]=mx[j-1][i];
         else
            mx[j][i]=mx[j-1][i+p[j-1]];
      }
}
int maxrmq(int a,int b) {
   int k=tlog[b-a+1];
   int ret;
   if(val[ mx[k][a] ]>val[ mx[k][b-p[k]+1] ]) ret=mx[k][a];
   else ret=mx[k][b-p[k]+1];
   return ret;
}
void init_rmq() {
   for(int i=0;i<=20;i++) p[i]=(1<<i);
   tlog[0]=-1;
   for(int i=1;i<=50000;i++)
      tlog[i]=(i&(i-1))?tlog[i-1]:tlog[i-1]+1;
}

**************************************************************************************************************
②一维RMQ模版
int n,q;
int a[N];
int mx[20][N],mi[20][N];
int tlog[N];
int p[21];

void make_maxrmq() {
   int i,j,k;
   for(i=1;i<=n;i++) mx[0][i]=a[i];
   for(j=1;p[j]<=n;j++)
      for(i=1;i+p[j]-1<=n;i++)
         mx[j][i]=max(mx[j-1][i],mx[j-1][i+p[j-1]]);
}
void make_minrmq() {
   int i,j,k;
   for(i=1;i<=n;i++) mi[0][i]=a[i];
   for(j=1;p[j]<=n;j++)
      for(i=1;i+p[j]-1<=n;i++)
         mi[j][i]=min(mi[j-1][i],mi[j-1][i+p[j-1]]);
}
int maxrmq(int a,int b) {
   int k=tlog[b-a+1];
   return max(mx[k][a],mx[k][b-p[k]+1]);
}
int minrmq(int a,int b) {
   int k=tlog[b-a+1];
   return min(mi[k][a],mi[k][b-p[k]+1]);
}
void init() {
   for(int i=0;i<=20;i++) p[i]=(1<<i);
   tlog[0]=-1;
   for(int i=1;i<=50000;i++)
      tlog[i]=(i&(i-1))?tlog[i-1]:tlog[i-1]+1;
}

int main()
{
   init();
   int s,t;
   while(scanf("%d%d",&n,&q)!=EOF) {

      for(int i=1;i<=n;i++) scanf("%d",&a[i]);

      make_maxrmq();
      make_minrmq();

      while(q--) {
         scanf("%d%d",&s,&t);
         printf("%d\n",maxrmq(s,t)-minrmq(s,t));
      }
   }
}

**************************************************************************************************************
③二维RMQ模板
==========================================================================================
①【普通版】
int n,m,q;
int a[N][N];
int mx[10][10][N][N];
int tlog[N];
int p[11];
void make_maxrmq() {
   int i,j,k,l;
   for(i=0;i<=n;i++)
      for(j=0;j<=m;j++)
         mx[0][0][i][j]=a[i][j];
   for(i=0;p[i]<=n;i++) {
      int di=p[i];
      for(j=0;p[j]<=m;j++) {
         if(i==0&&j==0) continue;
         int dj=p[j];
         for(k=1;k+di-1<=n;k++) {
            for(l=1;l+dj-1<=m;l++) {
               if(i==0)
                  mx[i][j][k][l]=max(mx[i][j-1][k][l],mx[i][j-1][k][l+p[j-1]]);
               else
                  mx[i][j][k][l]=max(mx[i-1][j][k][l],mx[i-1][j][k+p[i-1]][l]);
            }
         }
      }
   }
}
int maxrmq(int x1,int x2,int y1,int y2) {
   int kn=tlog[x2-x1+1]; //(int)(log(x2-x1+1.0)/log(2.0));
   int km=tlog[y2-y1+1]; //(int)(log(y2-y1+1.0)/log(2.0));
   int v1=mx[kn][km][x1][y1];
   int v2=mx[kn][km][x1][y2-p[km]+1];
   int v3=mx[kn][km][x2-p[kn]+1][y1];
   int v4=mx[kn][km][x2-p[kn]+1][y2-p[km]+1];
   return max(max(v1,v2),max(v3,v4));
}
void init_rmq() {
   for(int i=0;i<=10;i++) p[i]=1<<i;
   tlog[0]=-1;
   for(int i=1;i<=300;i++)
      tlog[i]=(i&(i-1))?tlog[i-1]:tlog[i-1]+1;
}
int main()
{
   init_rmq();
   int i,j;
   int x1,x2,y1,y2;
   while(scanf("%d%d",&n,&m)!=EOF) {
      for(i=1;i<=n;i++)
         for(j=1;j<=m;j++) scan_d(a[i][j]);
      make_maxrmq();
      scanf("%d",&q);
      while(q--) {
         scan_d(x1); scan_d(y1);
         scan_d(x2); scan_d(y2);

         int ans=maxrmq(x1,x2,y1,y2);
         printf("%d ",ans);
         if(ans==a[x1][y1]||ans==a[x1][y2]||ans==a[x2][y1]||ans==a[x2][y2])
            puts("yes");
         else
            puts("no");
      }
   }
   return 0;
}
==========================================================================================
②【终极版】
//数组优化:四维降三维
//二维RMQ,区间求最值
// + tlog[] 优化
int n,m,q;
int val[N][N];
int mx[10][N][N];
int tlog[N];
int pw[11];
void make_maxrmq() {
   int i,j,k;
   int nn=max(n,m);
   for(k=0;pw[k]<=nn;k++)
      for(i=1;i<=n;i++)
         for(j=1;j<=m;j++) mx[k][i][j]=val[i][j];
   for(k=1;pw[k]<=nn;k++) {
      for(i=1;i<=n;i++) {
         for(j=1;j<=m;j++) {
            mx[k][i][j]=mx[k-1][i][j];
            if(i+pw[k-1]<=n)
               mx[k][i][j]=max(mx[k][i][j],mx[k-1][i+pw[k-1]][j]);
            if(j+pw[k-1]<=m)
               mx[k][i][j]=max(mx[k][i][j],mx[k-1][i][j+pw[k-1]]);
            if(i+pw[k-1]<=n&&j+pw[k-1]<=m)
               mx[k][i][j]=max(mx[k][i][j],mx[k-1][i+pw[k-1]][j+pw[k-1]]);
         }
      }
   }
}
int maxrmq(int x1,int y1,int x2,int y2) {
   int i=tlog[x2-x1+1]; //(int)(log(x2-x1+1.0)/log(2.0));
   int j=tlog[y2-y1+1]; //(int)(log(y2-y1+1.0)/log(2.0));
   int k=min(i,j);
   if(i>j) i=j;
   int ret=mx[0][x1][y1];
   for(i=x1;i<=x2;i+=pw[k]) {
      if(i+pw[k]>x2) i=x2-pw[k]+1;
      for(j=y1;j<=y2;j+=pw[k]) {
         if(j+pw[k]>y2) j=y2-pw[k]+1;
         ret=max(ret,mx[k][i][j]);
      }
   }
   return ret;
}
void init_rmq() {
   for(int i=0;i<=10;i++) pw[i]=1<<i;
   tlog[0]=-1;
   for(int i=1;i<=300;i++)
      tlog[i]=(i&(i-1))?tlog[i-1]:tlog[i-1]+1;
}
int main()
{
   init_rmq();
   int i,j;
   int x1,x2,y1,y2;
   while(scanf("%d%d",&n,&m)!=EOF) {
      for(i=1;i<=n;++i)
         for(j=1;j<=m;++j) scan_d(val[i][j]);
      make_maxrmq();
      scanf("%d",&q);
      while(q--) {
         scan_d(x1); scan_d(y1);
         scan_d(x2); scan_d(y2);
         int ret=maxrmq(x1,y1,x2,y2);
         printf("%d ",ret);
         if(ret==val[x1][y1]||ret==val[x1][y2]||ret==val[x2][y1]||ret==val[x2][y2])
            puts("yes");
         else
            puts("no");
      }
   }
   return 0;
}
**************************************************************************************************************
**************************************************************************************************************