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; }