Frequent values

题目链接:https://vjudge.net/problem/POJ-3368

思路

我的代码有两个预处理:
第一个init: 将数组中的相等的元素,用首项是1,公差是1的等差数列表示,放在cnt[]中 然后用R[]数组,来表示某个元素所在段的下一段的起点 这个初始化,可以把我代码中的cnt[]和R[]打印出来,一看就能明白
预处理init_st:
就是对于cnt这个数组,求区间最大值。
处理的时候,有可能L所在段是被切断的,所以第一段可能不完整,但是在一段内cnt[]是一个前缀和,所以可以通过上面R[]定位到下一段的开始,就可以用前缀和高出这一段的元素个数,然后l = R[l]就把l移动到下一段的开始,然后直接查ST表就得出了[l,r]区间cnt[]中的最大值

代码

#include <iostream>
#include <algorithm>
#include <cmath>
#include <stdio.h>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 1e5+10;
using namespace std;

int N,Q;
int arr[maxn];
int cnt[maxn],R[maxn];
int st[maxn][30];

inline void read(int &x){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    x = s*w;
}

void init_st(){
    for(int i = 1;i<=N;i++) st[i][0] = cnt[i];
    int len = log(N)/log(2);
    for(int j = 1;j<=len;j++){
        for(int i = 1;i<=N-(1<<j)+1;i++){
            st[i][j] = max(st[i][j-1],st[i + (1<<(j-1))][j-1]);
        }
    }
}
void init(){
    arr[0] = -2e9;
    for(int i = 1;i<=N;i++){
        if(arr[i] != arr[i-1]) cnt[i] = 1;
        else cnt[i] = cnt[i-1] + 1;
    }
    int last = N+1;
    for(int i = N;i>=1;i--){
        R[i] = last;
        if(cnt[i] == 1) last = i;
    }
}
int main(){
    while(scanf("%d",&N)){
        if(N == 0) break;read(Q);
        for(int i = 1;i<=N;i++) read(arr[i]);
        init();
        init_st();
        while(Q--){
            int l,r;read(l),read(r);
            int ans = cnt[min(R[l]-1,r)] - cnt[l] + 1;
            l = R[l];
            if(l<=r){
                int len = log(r-l+1)/log(2);
                ans = max(ans,max(st[l][len],st[r-(1<<len)+1][len]));
            }
            printf("%d\n",ans);
        }

    }

    return 0;
}