单次期望 O(1) 的RMQ

万弘,太强了!!!

刚刚变态的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;
}
原文地址:https://www.cnblogs.com/Point-King/p/13720544.html