实现RMQ的两种常用方法

RMQ

  RMQ(Range Maximum/Minimum Question)是指区间最值问题,在OI中较为常见,一般可以用ST表和线段树实现。

  ST表是基于倍增思想的一种打表方法,在确定区间范围和所有的值后利用倍增预处理出$2^k$长度的区间内的最值,然后$O(1)$查询。优点是查询快且操作简便,缺点是不能进行动态操作,只支持静态查询。

  Code:(POJ模板题

//It is made by HolseLee on 23rd July 2018
//POJ 3264
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<iomanip>
using namespace std;
const int N=5e4+7;
int n,m,a[N];
int mx[N][25],mi[N][25];
inline int read()
{
  char ch=getchar();int num=0;bool flag=false;
  while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
  while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
  return flag?-num:num;
}
void ready()
{
  for(int j=1;j<=21;j++)
    for(int i=1;i<=n;i++)
      if(i+(1<<(j-1))<=n){
    mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
    mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);}
}
inline int quary(int l,int r)
{
  int maxx=-1,minn=998244353;
  int k=(int)(log((double)(r-l+1))/log(2.0));
  maxx=max(mx[l][k],mx[r-(1<<k)+1][k]);
  minn=min(mi[l][k],mi[r-(1<<k)+1][k]);
  return maxx-minn;
}
int main()
{
  n=read();m=read();
  memset(mx,-1,sizeof(mx));
  memset(mi,0x7f,sizeof(mi));
  for(int i=1;i<=n;i++){
    a[i]=read();
    mi[i][0]=mx[i][0]=a[i];}
  ready();int x,y;
  for(int i=1;i<=m;i++){
    x=read();y=read();
    printf("%d\n",quary(x,y));}
  return 0;
}

  线段树就不用多说了,还可以同时维护最大和最小值,操作同样也方便,而且还支持动态操作。

  Code:

//It is made by HolseLee on 23rd July 2018
//POJ 3264
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<iomanip>
using namespace std;
const int N=5e4+7;
int n,m,a[N];
struct Node{
    int mx,mi;
    Node(int xx=0,int yy=0)
    {mx=xx;mi=yy;}
}seg[N<<4];
inline int read()
{
    char ch=getchar();int num=0;bool flag=false;
    while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
    while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
    return flag?-num:num; 
}
inline void update(int rt)
{
    seg[rt].mx=max(seg[rt<<1].mx,seg[rt<<1|1].mx);
    seg[rt].mi=min(seg[rt<<1].mi,seg[rt<<1|1].mi);
}
inline void build(int l,int r,int rt)
{
    if(l>r)return;
    if(l==r){
        seg[rt].mx=seg[rt].mi=a[l];return;}
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);build(mid+1,r,rt<<1|1);
    update(rt);
}
inline Node quary(int l,int r,int rt,int L,int R)
{
    Node ret(-1,998244353);
    if(l>R||r<L)return ret;
    if(L<=l&&r<=R){return seg[rt];}
    int mid=(l+r)>>1;
    Node lc(-1,998244353);
    Node rc(-1,998244353);
    if(L<=mid)lc=quary(l,mid,rt<<1,L,R);
    if(R>mid)rc=quary(mid+1,r,rt<<1|1,L,R);
    ret.mx=max(lc.mx,rc.mx);
    ret.mi=min(lc.mi,rc.mi);
    return ret;
}
inline int get(int x,int y)
{
    int maxx=quary(1,n,1,x,y).mx;
    int minn=quary(1,n,1,x,y).mi;
    return maxx-minn;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
    a[i]=read();
    build(1,n,1);int x,y;
    for(int i=1;i<=m;i++){
        x=read();y=read();
        printf("%d\n",get(x,y));}
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/cytus/p/9356413.html
今日推荐