BMQ问题就是在一系列连续的数中,找出一个区间内最小的数,基本思路就是用d[i][j]表示从i开始,长度为2^j的一段元素中的最小值,直接先递推预处理,时间是O(nlogn),查找就O(1)
基本模板:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 10000;
int d[maxn][maxn];
void RMQ_init(int a[], int n)
{
for (int i = 0; i < n; i++)
d[i][0] = a[i];
for(int j=1;(1<<j)<=n;j++)
for (int i = 0; i + (1 << j)<= n; i++)
{
d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
}
}
int RMQ(int L, int R)
{
int k = 0;
while ((1 << (k + 1)) <= R - L + 1)
k++;
return min(d[L][k], d[R - (1 << k) + 1][k]);
}
int main()
{
int n;
int a[maxn];
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
RMQ_init(a,n);
printf("%d\n", RMQ(1, 7));
return 0;
}
例题8 UVa11235
题意:
看白书
要点:
一开始先进行游码编程,可以看出最左边和右边是没有办法进行预处理的,因为可能只截取了一半,所以我们将两个边界l,r的左右边界记录下来特殊处理,中间的直接RMQ即可。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100005;
int coun[maxn], num[maxn], Left[maxn], Right[maxn];
int tot,n,q,a,last;
int dp[maxn][25];
void RMQ_init()
{
for (int i = 1; i <= tot; i++) dp[i][0] = coun[i];
for (int j = 1; (1 << j) <= tot; j++)
for (int i = 1; i + (1 << j) <= tot; i++)
dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
}
int RMQ(int L, int R)
{
if (L > R)
return 0;
int k = 0;
while ((1 << (k + 1)) <= R - L + 1) k++;
return max(dp[L][k], dp[R - (1 << k) + 1][k]);
}
int main()
{
while (~scanf("%d", &n)&&n)
{
scanf("%d", &q);
tot = 0;
memset(num, 0, sizeof(num));
memset(coun, 0, sizeof(coun));
memset(Left, 0, sizeof(Left));
memset(Right, 0, sizeof(Right));
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
{
scanf("%d", &a);
if (i == 1)
{
tot++;
Left[tot]++;
last = a;
}
if (last == a)
{
num[i] = tot;
Right[tot]++;
coun[tot]++;
}
else
{
num[i] = ++tot;
coun[tot]++;
Left[tot] = Right[tot] = i;
last = a;
}
}
RMQ_init();
int l, r;
for (int i = 1; i <= q; i++)
{
scanf("%d%d", &l, &r);
if (num[l] == num[r])
printf("%d\n", r - l + 1);
else
printf("%d\n", max(RMQ(num[l] + 1, num[r] - 1), max(r-Left[num[r]] + 1, Right[num[l]] - l + 1)));
}
}
return 0;
}