虽然听说这是一道RMQ裸题,但是作为一个男人就要接受挑战。(其实是想记住这一种预处理的方式,否则也不会记录这么个RMQ裸题)
证明线段树确实能搞定它
本题就是求L,R内 最长 连续 相同数字 的长度
因为线段树能做区间max,min,和sum
进行O(3 * N)的预处理就可以直接O(lgN)查询了
第一步
把每段连续区间的最后一位(我们命名为计数点)记录这段连续区间长度
第二步
记录连续区间的点(非计数点),在这段区间内的位置 以负数形式记录下来
第三步
记录 每个非计数点 到这个区间的 计数点 需要的距离
预处理过程已经结束
然后直接线段树查 [ L , R ]区间内的最值Max,并且注意 左右两端的 不完整区间 是不是比 [L,R]内的完整区间长(L,R内都是相同数字的情况 要和你查询的 Max 取个最大值)
(橙色区域就是不完整区间)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <set>
#include <vector>
#include <stack>
#define Clear( x , y ) memset( x , y , sizeof(x) );
#define Qcin() std::ios::sync_with_stdio(false);
using namespace std;
typedef long long LL;
const int Maxn = 1e5 + 7;
const int Inf = 1e9 + 7;
LL A[Maxn];
LL C[Maxn] , To[Maxn];
LL N , Q;
struct edge{
LL l , r;
LL max , lazy;
}tree[Maxn * 5];
void PushUp( LL x ){
tree[x].max = max( tree[x*2].max , tree[x*2+1].max);
}
void Build( LL l , LL r , LL x ){
tree[x].l = l , tree[x].r = r;
if( l == r ){
tree[x].max = A[l];
return;
}
LL mid = ( l + r ) / 2;
Build( l , mid , x * 2 );
Build( mid + 1 , r , x * 2 + 1 );
PushUp( x );
}
LL Query( LL L , LL R , LL x ){
if( L <= tree[x].l && tree[x].r <= R ){
return tree[x].max;
}
LL mid = ( tree[x].l + tree[x].r ) / 2;
LL res = 0LL;
if( L <= mid ) res = max( res , Query( L , R , x * 2 ) );
if( R > mid ) res = max( res , Query( L , R , x * 2 + 1 ) );
return res;
}
void OPT(){
for(int i = 1 ; i <= N ; i++){
printf("%lld ", A[i]);
}
printf("\n");
for(int i = 1 ; i <= N ; i++){
printf("%lld ", To[i]);
}
printf("\n");
}
int main()
{
while(~scanf(" %lld",&N) && N){
scanf(" %lld",&Q);
Clear(A , 0); Clear(To , 0);
for(LL i = 1 ; i <= N ; i++){
scanf(" %d",&C[i]);
}
if(N == 1) A[1] = 1;
C[N+1] = 1000007;
LL cnt = 1LL;
for(LL i = 2 ; i <= N+1 ; i++){
if(C[i] == C[i-1]){
cnt++;
} else{
A[i-1] = cnt;
cnt = 1LL;
}
}
cnt = -1;
for(LL i = 1LL ; i <= N ; i++){
if(A[i]){
cnt = -1;
} else{
A[i] = cnt;
cnt--;
}
}
for(LL i = N ; i >= 1 ; i--){
if(A[i] >= 0){
cnt = A[i];
} else{
To[i] = cnt + A[i];
}
}
Build(1LL , N , 1LL);
LL L , R , dL , ans;
while(Q--){
scanf(" %lld %lld",&L , &R);
if(To[L-1] >= R - L + 1){
printf("%lld\n",R - L + 1);
continue;
} else{
dL = L-1 + To[L-1] + 1;
ans = max( dL-L , Query(dL , R , 1LL) );
if(A[R] < 0){
if(-A[R] > R-L+1) ans = max(ans , R-L+1);
else ans = max(ans , -A[R]);
}
printf("%lld\n",ans);
}
}
}
}