分块思想就是把一个区间拆成几份,利用每一份的最大值和边界中暴力每一个小块,就可以在nlog(n)算出区间最大值最小值。和二分相似,也就是n分的思想,当然,代码还是难调
(1)需要注意的是,当left和right在一个块内的时候,要特判一下,要不然,就会让最大值出现问题,扩大了这个区间的长度
(2)一般都是分成sqrt(n)块,每一块的左边界和右边界要单独做好,还有,最后一块如果不够一块,右边界改为n
(3)要用快读,分块会被卡长,加上register最好
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int Maxn=1e5+5;
const int Maxm=500;
int n,siz,tot,m,ans;
int a[Maxn],blg[Maxn],L[Maxm],R[Maxm],maxx[Maxm];
inline int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int main()
{
n=read();m=read();
siz=(int)sqrt(n);
for(register int i=1;i<=n;i++)
{
a[i]=read();
blg[i]=(i-1)/siz+1;//块从1开始
if(a[i]>maxx[blg[i]]) maxx[blg[i]]=a[i];
tot=blg[i];
}
for(register int i=1;i<=tot;i++)
{
L[i]=(i-1)*siz+1;
R[i]=siz*i;
}
R[tot]=n;
for(register int i=1,l,r;i<=m;i++)
{
l=read();r=read();
ans=-1e9;
if(blg[l]==blg[r])
{
for(register int j=l;j<=r;j++)
{
if(a[j]>ans) ans=a[j];
}
printf("%d\n",ans);
continue;
}
for(register int j=l;j<L[blg[l]+1];j++)
{
if(a[j]>ans) ans=a[j];
}
for(register int j=blg[l]+1;j<blg[r];j++)
{
if(maxx[j]>ans) ans=maxx[j];
}
for(register int j=L[blg[r]];j<=r;j++)
{
if(a[j]>ans) ans=a[j];
}
printf("%d\n",ans);
}
return 0;
}