膜万弘
,太强了!!!
刚刚变态的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('
');
continue;
}
ans=max(suf[x],pre[y]);
ans=max(ans,s[bel[x]+1][bel[y]-1]);
write(ans),putchar('
');
}
return 0;
}