1.题目描述:点击打开链接
2.解题思路:本题属于RMQ问题。注意到整个数组是非降序的,所有相等的元素都会聚在一起,这样就可以把整个数组进行游程编码(Run Lengh Encodeing RLE)。比如-1,1,2,2,2,4就可以表示为(-1,1),(1,2),(2,3),(4,1)。其中(a,b)表示有b个连续的a。本题中,用Left[pos],Right[pos]分别表示位置pos所在段的左右端点的位置。p[i]表示第i段的元素个数。那么每次查询(L,R)的结果为以下三部分的最大值:从L到Right[L]处的元素个数,从Left[R]到R的元素个数,区间Right[L]+1到Left[R]-1之间的最大值,其中这段区间可以利用Sparse-table算法解决。特殊情况:如果L和R在同一段,那么答案就是R-L+1。
3.代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;
#define N 100000+10
int A[N];
int n, q, e;
int C[N][20], Left[N], Right[N];
int p[N];
void init()
{
for (int i = 0; i < n; i++)
C[i][0] = p[i];
for (int j = 1; (1 << j) <= n;j++)
for (int i = 0; i + (1 << j) < n; i++)
C[i][j] = max(C[i][j - 1], C[i + (1 << j - 1)][j - 1]);
}
int Query(int L, int R)
{
int k = log((double)R - L + 1) / log(2.0);
return max(C[L][k], C[R - (1 << k) + 1][k]);
}
int main()
{
//freopen("t.txt", "r", stdin);
while (~scanf("%d", &n) && n)
{
scanf("%d", &q);
for (int i = 0; i < n; i++)
scanf("%d", A + i);
memset(p, 0, sizeof(p));
int pos = 0;
Left[0] = 0, p[0] = 1;
for (int i = 1; i < n; i++)
{
if (A[i] == A[i - 1])
p[i] = p[i - 1] + 1;//数组p统计每段的个数,先进行累加,最后分别以每段最后的统计结果为准,进行统一
else
{
pos = i;
p[i] = 1;
}
Left[i] = pos;
}
pos = n - 1, Right[pos] = pos;
for (int i = n - 2; i >= 0; i--)
{
if (A[i] == A[i + 1])
p[i] = p[i + 1];//以每段的最后一个数为准,将个数统一
else pos = i;
Right[i] = pos;
}
init();
while (q--)
{
int s, t;
scanf("%d%d", &s, &t);
s--, t--;
int ans = 0;
if (A[s] == A[t])ans = t - s + 1;//特殊情况
else
{
if (Right[s] + 1 < Left[t] - 1)//三段的最大值
ans = Query(Right[s] + 1, Left[t] - 1);
ans = max(ans, Right[s] - s + 1);
ans = max(ans, t - Left[t] + 1);
}
printf("%d\n", ans);
}
}
return 0;
}