1. 程式人生 > 實用技巧 >單次期望 O(1) 的RMQ

單次期望 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('\n');
			continue;
		}
		ans=max(suf[x],pre[y]);
		ans=max(ans,s[bel[x]+1][bel[y]-1]);
		write(ans),putchar('\n');
	}
	return 0;
}