單次期望 O(1) 的RMQ
阿新 • • 發佈:2020-09-23
膜萬弘
,太強了!!!
剛剛變態的zjjws
想要將一個需要 \(RMQ\) 問題的時間和空間都卡成 \(O(n)\) ,就在可憐的蒟蒻 Point_King
一籌莫展之時萬弘
他出現了,給予了本劇弱光明和力量——用分塊來做 \(RMQ\) 。
我們對於每一個塊,都預處理好字首和字尾的最值,同時對於 \(\sqrt n\) 個塊,我們預處理好每一個區間的最值,這部分的複雜度是 \(O(n)\) 。
然後查詢。如果區間位於同一個塊中,就暴力去做,如果不位於同一個塊中,我們就可以利用前面預處理的東西來 \(O(1)\) 查詢。
由於區間位於同一個塊中的概率是 \(\sqrt n\) ,所以這個方法的單次期望是 \(O(1)\)
以上。
程式碼如下:
#include<bits/stdc++.h> using namespace std; const int N=1e5+5,M=2e6+5,Sqrt=325; inline int read() { char c=getchar();int x=0; while(c<'0'||'9'<c) c=getchar(); while('0'<=c&&c<='9') x=x*10+c-'0',c=getchar(); return x; } inline void write(int x) { if(x>9) write(x/10); putchar(x%10+'0'); } int n,m,a[N]; int pre[N],suf[N]; int size,cnt=1,bel[N]; int s[Sqrt][Sqrt]; struct Piece { int l,r; void set() { pre[l]=a[l],suf[r]=a[r]; for(int i=l+1;i<=r;++i) pre[i]=max(pre[i-1],a[i]); for(int i=r-1;i>=l;--i) suf[i]=max(suf[i+1],a[i]); } }p[Sqrt]; int main() { n=read(),m=read(),size=sqrt(n); for(int i=1;i<=n;++i) a[i]=read(); for(int i=1;i<=n;i+=size,cnt++) { p[cnt].l=i,p[cnt].r=min(i+size-1,n); for(int j=i;j<=min(i+size-1,n);++j) bel[j]=cnt; } for(int i=1;i<=cnt;++i) p[i].set(); for(int i=1;i<=cnt;++i) { for(int j=i;j<=cnt;++j) s[i][j]=max(s[i][j-1],pre[p[j].r]); } for(int i=1,x,y,ans=0;i<=m;++i,ans=0) { x=read(),y=read(); if(bel[x]==bel[y]) { for(int j=x;j<=y;++j) ans=max(ans,a[j]); write(ans),putchar('\n'); continue; } ans=max(suf[x],pre[y]); ans=max(ans,s[bel[x]+1][bel[y]-1]); write(ans),putchar('\n'); } return 0; }