分块就是优雅的暴力搜索,就是把这一个数组分成好多块,每一块预处理最值,区间查询时,取这个区间里的每个块的最值,然后再求那些块覆盖不到的地方的最值(这个步骤暴力就行)
显然块的数量和块的大小不能太大也不能太小,所以我们把块的大小取 n \sqrt{n} n ,代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rp(i, e) for(int i=1;i<=(e);i++)
#define pr(i, e) for(int i=(e);i>=1;i--)
#define rp0(i, e) for(int i=0;i<(e);i++)
#define pr0(i, e) for(int i=(e-1);i>=0;i--)
#define rps(i, b, e) for(int i=(b);i<=(e);i++)
#define prs(i, e, b) for(int i=(e);i>=(b);i--)
#define rpg(i, x) for(int i=head[x];i;i=e[i].nxt)
using namespace std;
const int NR=1e5+10;
typedef long long LL;
int n, T, l, r, qm, bn, block[NR];
//qm-->每一个块的大小
//bn-->块的数量
//block[i]-->a[i]所属的块的编号
LL a[NR];
LL s[NR];//每一个块的最大值
inline int query(int l, int r)
{
int bl, br;
LL res=-1e18;
rp(i, bn)
{
bl=(i-1)*qm+1, br=min(i*qm, n);//块的左右元素
if(br<l)continue;
if(bl>r)break;
if(bl>=l && br<=r)res=max(res, s[i]);
else if(bl<l && br<=r)
rps(j, l, br)res=max(res, a[j]);
else rps(j, bl, r)res=max(res, a[j]);
}
return res;
}
int main()
{
scanf("%d%d", &n, &T);
qm=sqrt(n);
bn=n/qm+bool(n%qm);
memset(s, -999999, sizeof(s));
rp(i, n)
{
scanf("%lld", a+i);
block[i]=(i-1)/qm+1;
s[block[i]]=max(s[block[i]], a[i]);
}
while(T--)
{
scanf("%d%d", &l, &r);
printf("%d\n", query(l, r));
}
return 0;
}
80 pts ,虽然分块并不是专门用于 RMQ 和 RSQ ,但是可以维护很多别的东西
分块本质上还是一棵树,第一层是所有的树的集合,第二层是每一个块,第三层是每一个元素